以给定的精度比较FASM中的80位浮点

问题描述

我正在编写一个使用Nilakantha系列以至少0.05%的精度循环计算Pi的程序。此循环的退出条件应为当前计算值 res 和先前计算值 prev 符合| res-prev |的条件。

format PE console
entry start

include 'win32a.inc'


section '.code' code readable executable
; 3 + 4/(2*3*4) - 4 / (4*5*6) + 4/(6*7*8) - ...
start:
FINIT
piLoop:

; calculating denominator of fraction that will be added: x1*x2*x3
FLD [denominator]
FMUL [zero]
FADD [x1]
FMUL [x2]
FMUL [x3]
FSTP [denominator]

; changing denominator product values for next loop: x1 +=2,x2 += 2,x3 += 2
FLD [x1]
FADD [stepValue]
FSTP [x1]
FLD [x2]
FADD [stepValue]
FSTP [x2]
FLD [x3]
FADD [stepValue]
FSTP [x3]

;calculating numerator: multiplying numerator by -1
FLD [numerator]
FMUL [sign]
FSTP [numerator]

; calculating fraction: +-4 / (x1 * x2 * x3)
FLD [numerator]
FDIV [denominator]
FSTP [fraction]

; adding calculated fraction to our answer
FLD [res]
FADD [fraction]
FSTP [res]

; the comparison part,incorrect?
FLD [res]
FSUB [prev]
FABS
FCOM [accuracy]
FSTSW AX
SAHF

add [i],1


; prev = res
FLD [res]
FSTP [prev]
jb endMet
jmp piLoop
endMet:

invoke printf,steps_string,[i]

invoke getch
invoke ExitProcess,0

section '.data' data readable writable
steps_string db "Calculation completed. The Nilakantha Series took %d steps.",10,0
pi_string db "accurate pi = %lf,calculated pi = %lf",0


res dq 3.0
x1 dq 2.0
x2 dq 3.0
x3 dq 4.0
stepValue dq 2.0
fraction dq 0.0
numerator dq -4.0
denominator dq 0.0
sign dq -1.0
zero dq 0.0
N dd 20
i dd 0
accuracy dq 0.0005
calc dq ?
prev dq 3.0

section '.idata' import data readable
library kernel,'kernel32.dll',\
        msvcrt,'msvcrt.dll',\
        user32,'USER32.DLL'

include 'api\user32.inc'
include 'api\kernel32.inc'
import kernel,\
       ExitProcess,'ExitProcess',\
       HeapCreate,'HeapCreate',\
       HeapAlloc,'HeapAlloc'
include 'api\kernel32.inc'
import msvcrt,\
       printf,'printf',\
       sprintf,'sprintf',\
       scanf,'scanf',\
       getch,'_getch'  

解决方法

(只是扩展我的评论,以便得到答案。)

对于背景:浮点比较的指令序列很复杂,原因是早期的x86 CPU没有板载FPU。它是一个可选的单独芯片,并且它与CPU交互的能力受到限制。因此,FCOM指令无法直接设置CPU的FLAGS寄存器。而是设置浮点状态字,该字在浮点协处理器内部。 FSTSW指令可用于从协处理器获取状态字并将其加载到通用CPU寄存器中,然后SAHF将获取AH的适当位并将其写入FLAGS。

所有这些之后,您最终将FLAGS设置为指示比较结果,并布置状态字的位,以便以与整数比较相同的方式设置FLAGS:如果满足以下条件,则设置ZF:数字相等,如果差异严格为负,则CF,依此类推。因此,您现在可以像使用无符号整数比较一样使用jajb等条件跳转。请注意,PF = 1表示比较是无序的(至少一个操作数为NaN),因此您需要先检查一下。

(PPro添加了FCOMI,它通过FP对EFLAGS进行设置,与fcom / fstsw / sahf进行比较的方式相同,避免了额外的说明。另请参见Why do x86 FP compares set CF like unsigned integers,instead of using signed conditions?


但是,您的代码之间有add [i],1 ,并且像大多数x86算术指令一样,它会根据结果设置FLAGS。因此,您精心检索的标记将被覆盖,并且jb的后几行基于add而不是FCOM的结果。因此,您需要重新排列这些内容。

例如,在add之前执行SAHF。或在fcomi之前。

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...