【问题标题】:Is there a way to convert an integer to hex in NASM? [duplicate]有没有办法在 NASM 中将整数转换为十六进制? [复制]
【发布时间】:2021-03-30 05:09:22
【问题描述】:

如果有办法获得一个十进制值(0-9),有人可以向我解释一下吗?我正在做的一个项目需要它。我想做MOV SI, [CX:DX],但后来我有一种行不通的感觉。所以我决定在网上搜索,但我想要的主题不会出现。那么有人可以告诉我是否有办法从 0 到 9 获得 1 个十进制值?

我尝试过: MOV BL, 1000 MOV AH, 00h DIV DX

是不是我做错了什么?

将编译器 NASM 与 16 位代码一起使用。

【问题讨论】:

  • 从什么获取?无论如何,一般来说,使用除以 10 的余数。
  • 这不是更清楚。 1 个十进制数字 0-9 在十六进制中具有相同的值,因此无需转换。要获得一个数字,请使用模 10。您可能希望在 cx 中提供示例输入,并在 si 中提供预期输出,以便我们更好地理解。
  • 所以你想要最重要的十进制数字?一种选择是将输入除以 10000。如果商不为零,那就是您的结果。否则,将余数除以 1000,然后是 100,然后是 10。请注意,反向工作更简单,如果您对每次都除以 10 感到满意,但这样会以相反的顺序为您提供数字。
  • 除非您实际输出结果,否则您肯定会看到黑屏。但这是一个完全不同的问题。
  • 回复:标题问题:How to convert a binary integer number to a hex string?,或Printing hex values in x86 assembly(16 位)。但这似乎不是是你在做什么? How do I print an integer in Assembly Level Programming without printf from the c library? 用于从寄存器中的整数中提取以 10 为基数的数字,或 Displaying numbers with DOS

标签: assembly decimal nasm x86-16


【解决方案1】:

从 cmets 看来,您想要的是这样的:

;Input
; cx    Clock ticks since midnight
;
;Output
; ax    Most significant non-zero decimal digit of clocks since midnight (unless
;       clocks since midnight is zero, where zero will be returned)
;
;Trashed
; none (contents of all registers not used for outputs are preserved)

get_most_significant_decimal_digit:
    mov ax,cx           ;ax = numerator = clocks since midnight
    cmp ax,10           ;Is it already small enough?
    jb .done            ; yes

    push bx
    push dx

    mov bx,10           ;bx = divisor (constant value 10)
.continue:
    xor dx.dx           ;dx:ax = numerator zero extended to 32 bits
    div bx              ;ax = numerator / 10

    cmp ax,10           ;Is it small enough now?
    jae .continue       ; no, keep going

    pop dx
    pop bx
.done:
    ret

注意:为了获得最佳性能,最好为每个分区使用不同的除数,并选择除数以尽量减少除数。例如。 “如果不小于 10000,则除以 10000”然后“如果不小于 100,则除以 100”然后“如果不小于 10,则除以 10”。很难说性能改进是否值得额外的复杂性(以及更差的代码可读性)。

三思而后行;它并没有那么混乱(未经测试,NASM 语法):

    section .data
const10000:  dw 10000
const100:    dw 100
const10:     dw 10
    section .text

;Input
; cx    Clock ticks since midnight
;
;Output
; ax    Most significant non-zero decimal digit of clocks since midnight (unless
;       clocks since midnight is zero, where zero will be returned)
;
;Trashed
; none (contents of all registers not used for outputs are preserved)

get_most_significant_decimal_digit:
    mov ax,cx           ;ax = numerator = clocks since midnight
    push dx

    cmp ax,10000
    jb .l1
    xor dx,dx
    div word [const10000]
.l1:
    cmp ax,100
    jb .l2
    xor dx,dx
    div word [const100]
.l2:
    cmp ax,10
    jb .l3
    xor dx,dx
    div word [const10]
.l3:
    pop dx
    ret

对于这种替代方案,“更糟糕的情况”是 3 个部门和 3 个分支(而不是之前的方法的 4 个部门和 5 个分支)。

【讨论】:

  • 为了性能,您只需在比较/分支链之后划分一次。或者使用一个循环,将一个值乘以 10(从 1 或 10 开始)并进行比较,当您发现 10 的幂大于输入并使用前一个时停止。 (或乘以 10 溢出。)
  • 在您的更新中,您可以在分支链之前提升xor dx,dx。代码大小与div 执行次数的有趣权衡;如果div 不比 mul 或 code-fetch 慢很多,那可能没问题,并且适用于很多情况。
  • @PeterCordes:您可以拥有一棵分支树,树中的每个“端节点”都进行一次划分;但这将是“额外的复杂性(和更差的代码可读性)”并且(取决于它被调用的频率)甚至可能使性能更差(例如,错误预测的分支成本超过 2 个部门)。
  • @PeterCordes:是的,有很多替代品(另一种是像“if(ticks < 10) return ticks; else return table[ticks/2 - 5];”来减小表格大小);但大多数情况下,我只是在等待最初的提问者意识到他们的问题并不能反映他们真正想要的(或者因为他们想要所有数字的“整数到十进制 ASCII”,或者因为他们记得 BIOS“从午夜开始滴答作响”是实际上是cx:dx 中的 32 位值,而不是 16 位)。 ;)
  • @SepRoland:对于该代码,不需要const1000: dw 1000(从 1000 到 9999 的值将除以 100,然后除以 10)。
猜你喜欢
  • 2010-10-16
  • 2014-04-16
  • 1970-01-01
  • 2020-01-19
  • 2016-12-04
  • 1970-01-01
相关资源
最近更新 更多