NASM 协处理器 - 舍入效果不佳
NASM coprocessor - rounding works badly
我写了一个计算子弹体积的程序。对于 1.2 的半径,我应该得到 7(7.23 向下舍入)。相反,我得到 9.
我逐行查看了程序,但看不出哪里出错了。我的代码如下所示:
section .text
global _start
_start:
FINIT
FLD dword [radius] ;; st0 - radius
FLDPI ;; st0 - pi, st1 - radius
xor eax,eax
mov eax,4
mov [operator],eax
FLD dword [operator] ;; st0 - operator, st1 - pi, st2 - radius
mov eax,3
mov [operator2],eax
FLD dword [operator2] ;; st0- operator2, st1- operator, st2- pi, st3- radius
FXCH st1 ;; st0- operator, st1- operator2, st2- pi, st3- radius
FDIV st0,st1 ;; st0- operator/operator2 = 4/3, st1- operator2, st2- pi, st3- promien
FXCH st3 ;; radius, operator2, pi, operator/operator2
FMUL st0,st0 ;; st0- radius^2
FMUL st0,st0 ;; st0- radius^3
FMUL st0,st3 ;; st0- radius^3 * 4/3
FMUL st0,st2 ;; st0- radius^3 * 4/3 * pi
FISTP dword [result]
xor eax,eax
mov eax,[result]
add eax,48
mov [result],eax
mov eax,4
mov ebx,1
mov ecx,result
mov edx,4
int 80h
mov eax,1
int 80h
section .data
radius dd 1.2
operator dd 0
operator2 dd 0
result dd 0
您在这里尝试加载几个整数,就好像它们是 32 位浮点值一样:
mov eax,4
mov [operator],eax
FLD dword [operator] ;; st0 - operator, st1 - pi, st2 - promien
mov eax,3
mov [operator2],eax
FLD dword [operator2] ;; st0- operator2, st1- operator, st2- pi, st3- promien
要加载 32 位整数并将其转换为浮点数,您应该使用 FILD dword [foo]
。
来自英特尔软件开发人员手册:
FILD—Load Integer
Converts the signed-integer source operand into double extended-precision floating-point format and pushes the
value onto the FPU register stack. The source operand can be a word, doubleword, or quadword integer. It is loaded
without rounding errors. The sign of the source operand is preserved.
除了 Michael 提到的问题之外,您似乎使用的是 radius4 而不是 radius3
FMUL st0,st0 ;; st0- radius^2
FMUL st0,st0 ;; st0- radius^3 // r2 * r2 = r4, not r3
我写了一个计算子弹体积的程序。对于 1.2 的半径,我应该得到 7(7.23 向下舍入)。相反,我得到 9.
我逐行查看了程序,但看不出哪里出错了。我的代码如下所示:
section .text
global _start
_start:
FINIT
FLD dword [radius] ;; st0 - radius
FLDPI ;; st0 - pi, st1 - radius
xor eax,eax
mov eax,4
mov [operator],eax
FLD dword [operator] ;; st0 - operator, st1 - pi, st2 - radius
mov eax,3
mov [operator2],eax
FLD dword [operator2] ;; st0- operator2, st1- operator, st2- pi, st3- radius
FXCH st1 ;; st0- operator, st1- operator2, st2- pi, st3- radius
FDIV st0,st1 ;; st0- operator/operator2 = 4/3, st1- operator2, st2- pi, st3- promien
FXCH st3 ;; radius, operator2, pi, operator/operator2
FMUL st0,st0 ;; st0- radius^2
FMUL st0,st0 ;; st0- radius^3
FMUL st0,st3 ;; st0- radius^3 * 4/3
FMUL st0,st2 ;; st0- radius^3 * 4/3 * pi
FISTP dword [result]
xor eax,eax
mov eax,[result]
add eax,48
mov [result],eax
mov eax,4
mov ebx,1
mov ecx,result
mov edx,4
int 80h
mov eax,1
int 80h
section .data
radius dd 1.2
operator dd 0
operator2 dd 0
result dd 0
您在这里尝试加载几个整数,就好像它们是 32 位浮点值一样:
mov eax,4
mov [operator],eax
FLD dword [operator] ;; st0 - operator, st1 - pi, st2 - promien
mov eax,3
mov [operator2],eax
FLD dword [operator2] ;; st0- operator2, st1- operator, st2- pi, st3- promien
要加载 32 位整数并将其转换为浮点数,您应该使用 FILD dword [foo]
。
来自英特尔软件开发人员手册:
FILD—Load Integer
Converts the signed-integer source operand into double extended-precision floating-point format and pushes the value onto the FPU register stack. The source operand can be a word, doubleword, or quadword integer. It is loaded without rounding errors. The sign of the source operand is preserved.
除了 Michael 提到的问题之外,您似乎使用的是 radius4 而不是 radius3
FMUL st0,st0 ;; st0- radius^2
FMUL st0,st0 ;; st0- radius^3 // r2 * r2 = r4, not r3