Я пишу программу, которая вычисляет число Пи, используя серию Нилаканта в цикле с точностью не менее 0,05%. Условием выхода из этого цикла должно быть, когда текущее вычисленное значение res и ранее вычисленное значение prev соответствуют |res - prev| ‹= 0,0005. Я читал о некоторых сравнениях с плавающей запятой в FASM, но до сих пор не совсем понимаю, как это работает. В настоящее время программа просто выполняется бесконечно, никогда не выходя из цикла. Во время отладки я видел, как числа с плавающей запятой часто превращаются в 1.#IND00, что должно быть NaN. Как написать точное сравнение?
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", 10, 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'
FCOM / FSTSW / SAHF
кажется правильным, чтобы оставить результат сравнения во ФЛАГАХ, но тогда ожидается, что вы немедленно сделаете условный переход, чтобы фактически выполнить какое-то действие на основе результата сравнения. Вместо этого вы сначала делаетеadd [i], 1
, что перезаписывает флаги. - person Nate Eldredge   schedule 23.10.2020