Page 1 of 1
Infinity minus infinity bug
Posted: Tue Sep 19, 2023 7:14 am
by wilbert
The Asm and C backend disagree about the outcome of this but believe the C backend is right in this case.
Code: Select all
If Infinity() - Infinity() = 0.0
Debug "infinity minus infinity is zero"
Else
Debug "infinity minus infinity is not zero"
EndIf
If NaN() - NaN() = 0.0
Debug "not a number minus not a number is zero"
Else
Debug "not a number minus not a number is not zero"
EndIf
Re: Infinity minus infinity bug
Posted: Tue Sep 19, 2023 7:21 am
by STARGÅTE
Very strange, why this bug occur only during comparison?
Code: Select all
Define a.d = Infinity()
Debug Infinity()-Infinity()
Debug a-a
Debug Bool(Infinity()-Infinity()=0.0)
Debug Bool(a-a=0.0)
Debug Bool(Infinity()-a=0.0)
Debug Bool(a-Infinity()=0.0)
Re: Infinity minus infinity bug
Posted: Tue Sep 19, 2023 9:39 am
by wilbert
I looked into it some more.
I think it has to do with the flags.
UNORDERED: ZF,PF,CF := 111;
GREATER_THAN: ZF,PF,CF := 000;
LESS_THAN: ZF,PF,CF := 001;
EQUAL: ZF,PF,CF := 100;
The result of a floating point comparison is equal when the zero flag is set AND the parity flag is not set.
The C backend checks both the zero and parity flag to return the correct result.
I assume the Asm backend only checks the zero flag.
Re: Infinity minus infinity bug
Posted: Tue Sep 19, 2023 10:14 am
by juergenkulow
Code: Select all
; Bool(NaN()=0.0) is in ASM 1 and in C Backend 0
a=Bool(NaN()=0.0)
Debug a
; ASM Backend: 1
; ; a=Bool(NaN()=0.0)
; CALL PB_NaN_DOUBLE
; MOVSD [rsp-8],xmm0
; FLD qword [rsp-8]
; FCOMP qword [D1]
; FNSTSW ax
; TEST ah,40h
; _Bool0:
; JE .False
; MOV rax,1
; JMP .True
; .False:
; XOr rax,rax
; .True:
; MOV qword [v_a],rax
; 00401045 | E8 F60F0000 | call boolnanwinx86.402040 |
; 0040104A | DC1D 28404000 | fcomp st(0),qword ptr ds:[404028] |
; 00401050 | DFE0 | fnstsw ax |
; 00401052 | F6C4 40 | test ah,40 |
; 00401055 | 74 07 | je boolnanwinx86.40105E |
; 00401057 | B8 01000000 | mov eax,1 |
; 0040105C | EB 02 | jmp boolnanwinx86.401060 |
; 0040105E | 31C0 | XOr eax,eax |
; 00401060 | A3 30414000 | mov dword ptr ds:[404130],eax |
; C Backend: 0
; // a=Bool(NaN()=0.0)
; double r0=PB_NaN_DOUBLE();
; int r1=(((r0==0.0))?1:0);
; v_a=r1;
; 0000000140001051 | E8 4A040000 | call boolnanwin.1400014A0 |
; 0000000140001056 | 6648:0F7EC0 | movq rax,xmm0 |
; 000000014000105B | 48:8945 F8 | mov qword ptr ss:[rbp-8],rax |
; 000000014000105F | 66:0FEFC0 | pxor xmm0,xmm0 |
; 0000000140001063 | 66:0F2E45 F8 | ucomisd xmm0,qword ptr ss:[rbp-8] |
; 0000000140001068 | 0F9BC0 | setnp al |
; 000000014000106B | BA 00000000 | mov edx,0 |
; 0000000140001070 | 66:0FEFC0 | pxor xmm0,xmm0 |
; 0000000140001074 | 66:0F2E45 F8 | ucomisd xmm0,qword ptr ss:[rbp-8] |
; 0000000140001079 | 0F45C2 | cmovne eax,edx |
; 000000014000107C | 0FB6C0 | movzx eax,al |
; 000000014000107F | 48:8905 AA32000 | mov qword ptr ds:[140004330],rax |
; 00401049 | E8 62020000 | call boolnanwinx86.4012B0 |
; 0040104E | DD5D F0 | fstp qword ptr ss:[ebp-10],st(0) |
; 00401051 | DD45 F0 | fld st(0),qword ptr ss:[ebp-10] |
; 00401054 | D9EE | fldz |
; 00401056 | DFE9 | fucomip st(0),st(1) |
; 00401058 | DDD8 | fstp st(0),st(0) |
; 0040105A | 0F9BC0 | setnp al |
; 0040105D | BA 00000000 | mov edx,0 |
; 00401062 | DD45 F0 | fld st(0),qword ptr ss:[ebp-10] |
; 00401065 | D9EE | fldz |
; 00401067 | DFE9 | fucomip st(0),st(1) |
; 00401069 | DDD8 | fstp st(0),st(0) |
; 0040106B | 0F45C2 | cmovne eax,edx |
; 0040106E | 0FB6C0 | movzx eax,al |
; 00401071 | 8945 EC | mov dword ptr ss:[ebp-14],eax
Code: Select all
; Bool(NaN()=0.0) is in ASM 1 and in C Backend 0
Structure dq
StructureUnion
d.d ; also .f
q.q
EndStructureUnion
EndStructure
Define dq.dq\d=Infinity()
Debug dq\d
Debug Hex(dq\q)
Debug Bool(dq\d=0.0)
Define dq.dq\d=-Infinity()
Debug dq\d
Debug Hex(dq\q)
Debug Bool(dq\d=0.0)
Define dq.dq\d=NaN()
Debug dq\d
Debug Hex(dq\q)
Debug Bool(dq\d=0.0)
Define dq.dq\d=-NaN()
Debug dq\d
Debug Hex(dq\q)
Debug Bool(dq\d=0.0)
; ASM Backend
; +Infinity
; 7FF0000000000000
; 0
; -Infinity
; FFF0000000000000
; 0
; NaN
; 7FF8000000000000
; 1
; NaN
; FFF8000000000000
; 1
; C Backend
; +Infinity
; 7FF0000000000000
; 0
; -Infinity
; FFF0000000000000
; 0
; NaN
; 7FF8000000000000
; 0
; NaN
; FFF8000000000000
; 0
Is 1/0 Equal 0 Wolframalpha:false
Wrong result for comparisons with NaN (ASM backend)
Posted: Thu Feb 08, 2024 7:15 am
by STARGÅTE
Code: Select all
Define.d Number1 = NaN()
Define.d Number2 = 3.14
If Number1 > Number2
Debug StrD(Number1) + " > " + StrD(Number2)
EndIf
If Number1 < Number2
Debug StrD(Number1) + " < " + StrD(Number2)
EndIf
If Number1 = Number2
Debug StrD(Number1) + " = " + StrD(Number2)
EndIf
ASM wrote:NaN > 3.14
NaN = 3.14
C wrote:
Re: Wrong result for comparisons with NaN (ASM backend)
Posted: Thu Feb 08, 2024 8:10 am
by wilbert
Re: Wrong result for comparisons with NaN (ASM backend)
Posted: Thu Feb 08, 2024 10:52 am
by juergenkulow
Also Linux:
Code: Select all
/media/ramdisk/pb610B5/purebasic/compilers/pbcompiler /media/kulow/BCE4-8C0F/PB/NaN2.pb --commented --debugger
PureBasic 6.10 beta 5 (Linux - x64)
Loading external modules...
Starting compilation...
12 lines processed.
Creating the executable.
- Feel the ..PuRe.. Power -
[Debugger] NaN > 3.14
[Debugger] NaN = 3.14
/media/ramdisk/pb610B5/purebasic/compilers/pbcompiler Runtime:166 ms
Floatingpointstatusword in ax is $4501. (FPSW$INVALID #0001 An invalid result occurred)
Intel Floating-Point Reference Sheet
Re: Infinity minus infinity bug
Posted: Thu Feb 08, 2024 11:36 am
by Fred
wilbert wrote: Tue Sep 19, 2023 9:39 am
I looked into it some more.
I think it has to do with the flags.
UNORDERED: ZF,PF,CF := 111;
GREATER_THAN: ZF,PF,CF := 000;
LESS_THAN: ZF,PF,CF := 001;
EQUAL: ZF,PF,CF := 100;
The result of a floating point comparison is equal when the zero flag is set AND the parity flag is not set.
The C backend checks both the zero and parity flag to return the correct result.
I assume the Asm backend only checks the zero flag.
So TEST ax,40h is wrong ? How the test should be like ?
Re: Infinity minus infinity bug
Posted: Thu Feb 08, 2024 2:52 pm
by wilbert
The C compiler uses FUCOMIP instead of FCOMP for x86 and UCOMISD for x64.
Both FUCOMIP and UCOMISD set the zero, parity and carry flags so you don't have to store the status word in this case.
The parity flag is evaluated first. If it is set, the compared values are not equal.
If parity is not set, the zero flag is evaluated. It it is set, the compared values are equal, if not they are not equal.
So the code would look something like
Code: Select all
MOV eax, 1
FUCOMIP st0, st1
JP .False
JZ .True
.False:
XOR eax, eax
.True:
If you do want to use the status word, you can first invert the zero flag and then check the parity and zero flag together.
Code: Select all
FNSTSW ax
XOR ah, 0x40
TEST ah, 0x44
JNZ .False
MOV eax, 1
JMP .True
.False:
XOR eax, eax
.True: