将两个 32 位数字相乘并将 64 位结果打印为十进制 NASM 程序集
multiplying two 32-Bit Numbers and printing the 64 bit result as decimal NASM assembly
我在使用 NASM 程序集时遇到问题。
我不知道如何将 2 个数字相乘并将它们打印到屏幕上。
问题是我们只能使用一个只打印32位长度数字的函数;不是 64 位长度的数字。
所以我的问题可能是数学问题,我想我需要使用霍纳的方法来得到小数;就像我在下面指出的那样。
如果我有
AF / A = 11 remaining 5
11 / A = 1 remaining 7
1 / A = 0 remaining 1
-> 175 是正确的结果
但是当我在这里把它分成两个寄存器时,每个 4 字节就像一个例子
A | F A / A = 1 remaining 0 and F / A = 1 remaining 5
1 / A = 0 remaining 1
->150 这是错误的
这是我的汇编代码
mov eax, [Zahl1]
mul dword [Zahl2]
mov [High], edx
;---- low-----
mov ebx, 10
loopbegin:
;dividing by 10
xor edx, edx
div ebx
;counting
inc dword [counter]
;saving the number
push edx
cmp eax, 0
jne loopbegin
mov ebx, 10
; --- high ----
mov eax, [High]
highloop:
xor edx, edx
div ebx
inc dword [counter]
push edx
cmp eax, 0
jne highloop
<note>
这里遵循从堆栈打印数字的循环
你不能只转换+打印两半,因为高半部分的位代表整个64位数字中的4294967296 * hi
。
4294967296
不是 10 的幂,因此高半部分的位会影响小数点的低位。如果您以 2 的幂为基数打印,例如十六进制或八进制,您的方法会起作用,因为除以基数只是一个移位:即低十六进制数字仅由低 4 位确定。但是低位十进制数取决于所有64个二进制位。
相反,您需要进行 64 位除以 10。这需要多个 div
指令,因为如果商溢出 32 位,div r32
(64b / 32b => 32b) 会出错。 有关扩展精度除法 的工作代码,请参阅Assembler 64b division。 (但不要将 xchg
与内存一起使用;而是使用一些额外的寄存器)。
(div
在现代 CPU 上很慢而 mul
非常快;可能值得进行扩展精度乘法以获得 64b * 64b => 128b 乘法的高半部分a fixed-point multiplicative inverse 除以 10 更快。)
此外,您不需要 push
数字,也不需要内存中的计数器。只需为从缓冲区末尾开始的指针使用一个额外的寄存器。周边代码的写法见How do I print an integer in Assembly Level Programming without printf from the c library?,只需用两条div
指令将内层循环中的32位除法替换为扩展精度即可。
我在使用 NASM 程序集时遇到问题。
我不知道如何将 2 个数字相乘并将它们打印到屏幕上。
问题是我们只能使用一个只打印32位长度数字的函数;不是 64 位长度的数字。
所以我的问题可能是数学问题,我想我需要使用霍纳的方法来得到小数;就像我在下面指出的那样。
如果我有
AF / A = 11 remaining 5
11 / A = 1 remaining 7
1 / A = 0 remaining 1
-> 175 是正确的结果
但是当我在这里把它分成两个寄存器时,每个 4 字节就像一个例子
A | F A / A = 1 remaining 0 and F / A = 1 remaining 5
1 / A = 0 remaining 1
->150 这是错误的
这是我的汇编代码
mov eax, [Zahl1]
mul dword [Zahl2]
mov [High], edx
;---- low-----
mov ebx, 10
loopbegin:
;dividing by 10
xor edx, edx
div ebx
;counting
inc dword [counter]
;saving the number
push edx
cmp eax, 0
jne loopbegin
mov ebx, 10
; --- high ----
mov eax, [High]
highloop:
xor edx, edx
div ebx
inc dword [counter]
push edx
cmp eax, 0
jne highloop
<note>
这里遵循从堆栈打印数字的循环
你不能只转换+打印两半,因为高半部分的位代表整个64位数字中的4294967296 * hi
。
4294967296
不是 10 的幂,因此高半部分的位会影响小数点的低位。如果您以 2 的幂为基数打印,例如十六进制或八进制,您的方法会起作用,因为除以基数只是一个移位:即低十六进制数字仅由低 4 位确定。但是低位十进制数取决于所有64个二进制位。
相反,您需要进行 64 位除以 10。这需要多个 div
指令,因为如果商溢出 32 位,div r32
(64b / 32b => 32b) 会出错。 有关扩展精度除法 的工作代码,请参阅Assembler 64b division。 (但不要将 xchg
与内存一起使用;而是使用一些额外的寄存器)。
(div
在现代 CPU 上很慢而 mul
非常快;可能值得进行扩展精度乘法以获得 64b * 64b => 128b 乘法的高半部分a fixed-point multiplicative inverse 除以 10 更快。)
此外,您不需要 push
数字,也不需要内存中的计数器。只需为从缓冲区末尾开始的指针使用一个额外的寄存器。周边代码的写法见How do I print an integer in Assembly Level Programming without printf from the c library?,只需用两条div
指令将内层循环中的32位除法替换为扩展精度即可。