在汇编中进行一些计算后继续得到 NaN
Keep getting NaN after doing some calculations in assembly
我正在开发一个求解二次方程根的程序。我能够在 root1 子例程中获得第一个根。但是,当我尝试求解 root2 中的第二个根时,二次公式的“/2a”部分始终产生 NaN。
代码如下:
INCLUDE Irvine32.inc
INCLUDE macros.inc
.data
a real8 ?
b real8 ?
cc real8 ?
a2 real8 ?
b2 real8 ?
cc2 real8 ?
two real8 2.0
four real8 4.0
two2 real8 2.0
four2 real8 4.0
ten real8 1000.0
num real8 10.0
.code
main PROC
finit
mWrite "Enter coefficient (a): "
call ReadFloat
fst a
fstp a2
mWrite "Enter coefficient (b): "
call ReadFloat
fst b
fstp b2
mWrite "Enter coefficient (c): "
call ReadFloat
fst cc
fstp cc2
mWrite "Roots: "
call root1
call Crlf
call root2
;call showfpustack
exit
main ENDP
root1 PROC
; b^2
fld b
fmul b
fchs ; flip sign
fst b
; 4 * a * c
fld four
fmul a
fmul cc
fchs
fsub b
fsqrt
fst four
fld b
fchs
fsqrt
fchs
fadd four
fst b
fld two
fmul a
fst two
fld b
fdiv two
call WriteFloat
call showfpustack
ret
root1 endp
root2 PROC
fld b2
fmul b2
fchs
fst b2
fld four2
fmul a2
fmul cc2
fchs
fsub b2
fsqrt
fst four2
fld b2
fchs
fsqrt
fchs
fsub four2
fst b2
call Crlf
call WriteFloat
fld two2
fmul a2
fst two2
fld b2
fdiv two2
call showfpustack
ret
root2 endp
end main
我能够验证之前的计算结果。我只是遇到了这部分问题。
我不会猜测您为什么会得到 NAN,而是会引导您完成计算二次方程的根所需编写的代码。
您会看到您不需要内存中的任何常量,也不需要输入的多个副本 a、b 和 c.
重置 FPU 环境
fninit
存储一个有趣的常量,我们将重复使用多次:
fld a ; (st0) a
fadd st0 ; (st0) a + a == 2a
计算 D = b^2 - 4ac
fld b ; (st0) b (st1) 2a
fmul st0 ; (st0) b * b == b^2 (st1) 2a
fld c ; (st0) c (st1) b^2 (st2) 2a
fmul st2 ; (st0) c * 2a == 2ac (st1) b^2 (st2) 2a
fadd st0 ; (st0) 2ac + 2ac == 4ac (st1) b^2 (st2) 2a
fsubp ; (st0) b^2 - 4ac == D (st1) 2a
这里我们需要测试 D 是否不为负,因为 D<0
.
不存在根
ftst ; This compares st0 to 0.0 and sets flags C3, C2, and C0
fnstsw ax ; Copies those flags to AX
sahf ; Copies those flags to EFLAGS
jp IsUnordered ; This should not happen
jc IsNegative ; This is very possible
只有当 D 不为负时,我们才能取平方根。
fsqrt ; (st0) sqrt(D) (st1) 2a
求第一个根 R1:
fld b ; (st0) b (st1) sqrt(D) (st2) 2a
fchs ; (st0) -b (st1) sqrt(D) (st2) 2a
fsub st1 ; (st0) -b - sqrt(D) (st1) sqrt(D) (st2) 2a
fdiv st2 ; (st0) (-b - sqrt(D)) / 2a == R1 (st1) sqrt(D) (st2) 2a
求第二个根 R2:
fld b ; (st0) b (st1) R1 (st2) sqrt(D) (st3) 2a
fchs ; (st0) -b (st1) R1 (st2) sqrt(D) (st3) 2a
fadd st2 ; (st0) -b - sqrt(D) (st1) R1 (st2) sqrt(D) (st3) 2a
fdiv st3 ; (st0) (-b - sqrt(D)) / 2a == R2 (st1) R1 (st2) sqrt(D) (st3) 2a
此时FPU寄存器栈只有4个条目:
st3 = 2a
st2 = sqrt(D)
st1 = R1
st0 = R2
请注意,在此代码中的任何地方我都不必将任何内容存储回内存。与 FPU 合作需要仔细规划。重新排列表达式通常是有利的,重新使用以前计算的值总是好的。
我正在开发一个求解二次方程根的程序。我能够在 root1 子例程中获得第一个根。但是,当我尝试求解 root2 中的第二个根时,二次公式的“/2a”部分始终产生 NaN。
代码如下:
INCLUDE Irvine32.inc
INCLUDE macros.inc
.data
a real8 ?
b real8 ?
cc real8 ?
a2 real8 ?
b2 real8 ?
cc2 real8 ?
two real8 2.0
four real8 4.0
two2 real8 2.0
four2 real8 4.0
ten real8 1000.0
num real8 10.0
.code
main PROC
finit
mWrite "Enter coefficient (a): "
call ReadFloat
fst a
fstp a2
mWrite "Enter coefficient (b): "
call ReadFloat
fst b
fstp b2
mWrite "Enter coefficient (c): "
call ReadFloat
fst cc
fstp cc2
mWrite "Roots: "
call root1
call Crlf
call root2
;call showfpustack
exit
main ENDP
root1 PROC
; b^2
fld b
fmul b
fchs ; flip sign
fst b
; 4 * a * c
fld four
fmul a
fmul cc
fchs
fsub b
fsqrt
fst four
fld b
fchs
fsqrt
fchs
fadd four
fst b
fld two
fmul a
fst two
fld b
fdiv two
call WriteFloat
call showfpustack
ret
root1 endp
root2 PROC
fld b2
fmul b2
fchs
fst b2
fld four2
fmul a2
fmul cc2
fchs
fsub b2
fsqrt
fst four2
fld b2
fchs
fsqrt
fchs
fsub four2
fst b2
call Crlf
call WriteFloat
fld two2
fmul a2
fst two2
fld b2
fdiv two2
call showfpustack
ret
root2 endp
end main
我能够验证之前的计算结果。我只是遇到了这部分问题。
我不会猜测您为什么会得到 NAN,而是会引导您完成计算二次方程的根所需编写的代码。
您会看到您不需要内存中的任何常量,也不需要输入的多个副本 a、b 和 c.
重置 FPU 环境
fninit
存储一个有趣的常量,我们将重复使用多次:
fld a ; (st0) a
fadd st0 ; (st0) a + a == 2a
计算 D = b^2 - 4ac
fld b ; (st0) b (st1) 2a
fmul st0 ; (st0) b * b == b^2 (st1) 2a
fld c ; (st0) c (st1) b^2 (st2) 2a
fmul st2 ; (st0) c * 2a == 2ac (st1) b^2 (st2) 2a
fadd st0 ; (st0) 2ac + 2ac == 4ac (st1) b^2 (st2) 2a
fsubp ; (st0) b^2 - 4ac == D (st1) 2a
这里我们需要测试 D 是否不为负,因为 D<0
.
ftst ; This compares st0 to 0.0 and sets flags C3, C2, and C0
fnstsw ax ; Copies those flags to AX
sahf ; Copies those flags to EFLAGS
jp IsUnordered ; This should not happen
jc IsNegative ; This is very possible
只有当 D 不为负时,我们才能取平方根。
fsqrt ; (st0) sqrt(D) (st1) 2a
求第一个根 R1:
fld b ; (st0) b (st1) sqrt(D) (st2) 2a
fchs ; (st0) -b (st1) sqrt(D) (st2) 2a
fsub st1 ; (st0) -b - sqrt(D) (st1) sqrt(D) (st2) 2a
fdiv st2 ; (st0) (-b - sqrt(D)) / 2a == R1 (st1) sqrt(D) (st2) 2a
求第二个根 R2:
fld b ; (st0) b (st1) R1 (st2) sqrt(D) (st3) 2a
fchs ; (st0) -b (st1) R1 (st2) sqrt(D) (st3) 2a
fadd st2 ; (st0) -b - sqrt(D) (st1) R1 (st2) sqrt(D) (st3) 2a
fdiv st3 ; (st0) (-b - sqrt(D)) / 2a == R2 (st1) R1 (st2) sqrt(D) (st3) 2a
此时FPU寄存器栈只有4个条目:
st3 = 2a
st2 = sqrt(D)
st1 = R1
st0 = R2
请注意,在此代码中的任何地方我都不必将任何内容存储回内存。与 FPU 合作需要仔细规划。重新排列表达式通常是有利的,重新使用以前计算的值总是好的。