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

Debug Infinity()-Infinity()
; NaN

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
I think it's related to this problem I posted before
https://www.purebasic.fr/english/viewtopic.php?p=607695

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: