Thank you, M.
On reading through some of the Fl-Point specs, etc, it seems that "comparisons" are not allowed, anyway! (with NANs, etc). So, as you say, it's a tricky subject.
Somewhat related, and mainly for lurkers, I wanted to investigate these QNANs, SNANs, #INFs, #INDs, etc, a little more. So I wrote some code to create them - to then see how they would be handled... And I hit another anomaly... I couldn't create some SNAN values, as I hope is explained in the comments at the start of this code:
Code: Select all
#include "string.bi"
'***********************************************************************************
' WARNNG: The CVD() and CVS() functions can be used to create Floating-point values.
' In some rare situations, these functions do not emit the expected Fl-Point fields.
'
' Specifically, if these functions are used to create some "SNAN" values (perhaps for
' program testing), then the actual Fl-Pt values created are QNANs.
'
' If direct ASM op-codes are used to create these Fl-Pt SNAN fields (instead of CVD()
' and CVS()), the same QNANs are also created, so the "issue" seems to NOT be in the
' FB functions, but in the Fl-Pt handlers of the CPU.
'
' (It's possible that this behaviour is actually intentional and correct, and part
' of the (Intel?) Fl-Pt spec, but I've not investigated this).
'
' - Michael Kennedy (Jan, 2018)
'***********************************************************************************
' A few definitions:
' - Double (fl-point): 8 bytes in total: exponent sign, 11-bit exponent, 52-bit mantissa (incl sign)
' - Single (fl-point): 4 bytes in total: exponent sign, 8-bit exponent, 23-bit mantissa (incl sign)
'***********************************************************************************
' Strange / Oddball situation?:
' When the strings going into CVD() and CVS() contain the following patterns:
' - Exponent-Sign = 0 or 1
' - Exponent = FFF (all bits set)
' - Mantissa-Sign = 0 <-----
' - Mantissa = any non-zero value
'
' Then, the emitted Fl-Point value has all the above contents, BUT, the Mantissa-Sign
' is forced to 1.
' - If the Mantissa-Sign is not changed (as might be expected!), the final Fl-Point
' value is defined as a "SNAN" (Signalling Not-A-Number).
' - With the Mantissa-Sign forced to "1", the final Fl-Point value is defined as a
' "QNAN" (Quiet NAN).
'
' The code below has a "Show_Oddball" option, to treat these strange conversions as
' acceptable, or unacceptable.
'***********************************************************************************
' Definitions of all major Floating-point values (b=bias)
'
' Exp Exponent Fraction Value
' Sign (e) (f)
' ---- ------------------ ------------------ -----
' 0 00...00 00...00 +0
' 0 00...00 00...01 to 11...11 Positive Denormalized Real 0.f × 2^(−b+1)
' 0 00...01 to 11...10 XX...XX Positive Normalized Real 1.f × 2^(e−b)
' 0 11...11 00...00 +∞ (infinity)
' 0 11...11 00...01 to 01...11 SNaN
' 0 11...11 1X...XX QNaN
' 1 00...00 00...00 −0
' 1 00...00 00...01 to 11...11 Negative Denormalized Real −0.f × 2^(−b+1)
' 1 00...01 to 11...10 XX...XX Negative Normalized Real −1.f × 2^(e−b)
' 1 11...11 00...00 −∞ (infinity)
' 1 11...11 00...01 to 01...11 SNaN
' 1 11...11 1X...XX QNaN
'***********************************************************************************
' Few simple Macros...
#Define is_INF_Sgl(__CHECKME__) _
((Cast( Integer Ptr, Varptr( __CHECKME__ ))[0] and &h7FFFFFFFul) = &h7F800000ul)
#Define is_QNAN_Sgl(__CHECKME__) _
((Not (is_INF_Sgl(__CHECKME__))) and ((Cast( Integer Ptr, Varptr( __CHECKME__ ))[0] and &h7FC00000ul) = &h7FC00000ul))
#Define is_SNAN_Sgl(__CHECKME__) _
((Not (is_INF_Sgl(__CHECKME__))) and ((Cast( Integer Ptr, Varptr( __CHECKME__ ))[0] and &h7FC00000ul) = &h7F800000ul))
#Define is_FP_Sgl(__CHECKME__) _
(Not ( is_QNAN_Sgl( __CHECKME__ ) Or is_SNAN_Sgl( __CHECKME__ ) Or is_INF_Sgl( __CHECKME__ ))) '(none of the above!)
#Define is_INF_Dbl(__CHECKME__) _
(((Cast( Integer Ptr, Varptr( __CHECKME__ ))[1] and &h7FFFFFFFul) = &h7FF00000ul) and _
((Cast( Integer Ptr, Varptr( __CHECKME__ ))[0] and &hFFFFFFFFul) = &h00000000ul)) '([0]=Lo 4 bytes, [1]=Hi 4 bytes)
#Define is_QNAN_Dbl(__CHECKME__) _
((Not (is_INF_Dbl(__CHECKME__))) and ((Cast( Integer Ptr, Varptr( __CHECKME__ ))[1] and &h7FF80000ul) = &h7FF80000ul))
#Define is_SNAN_Dbl(__CHECKME__) _
((Not (is_INF_Dbl(__CHECKME__))) and ((Cast( Integer Ptr, Varptr( __CHECKME__ ))[1] and &h7FF80000ul) = &h7FF00000ul))
#Define is_FP_Dbl(__CHECKME__) _
(Not ( is_QNAN_Dbl( __CHECKME__ ) Or is_SNAN_Dbl( __CHECKME__ ) Or is_INF_Dbl( __CHECKME__ ))) '(none of the above!)
'***********************************************************************************
Declare sub Check_Bits_Dbl (byref d as double, byref u64 as ulongint)
Declare sub Check_Bits_Sgl (byref d as single, byref u32 as ulong)
Declare Sub Do_Asm_Dbl (ByRef i as ulongint, ByRef d as double)
Declare Sub Do_Asm_Sgl (ByRef i as ulong, ByRef s as single)
dim shared as string show_oddball
dim as double d
dim as single s
dim as ulongint u64 '(64-bit)
dim as ulong u32 '(32-bit)
'***********************************************************************************
print
print "Investigate unusual Floating-point numbers - SNAN, QNAN, #IND, #INF, etc v.1.0"
print
input "Show the Oddball conversion from SNAN to QNAN? (default=N): "; Show_Oddball
Show_Oddball = UCase(Left(Trim(Show_Oddball),1))
If Show_Oddball <> "Y" then Show_Oddball = ""
print "==============================================================================="
print "DOUBLES (Few ordinary values)..."
print "==============================================================================="
u64 = &h3ff3333333333333: Check_Bits_Dbl(d,u64) 'Value: 1.2
u64 = &h40C81CD6E696A26E: Check_Bits_Dbl(d,u64) 'Value: 12345.678912
print "==============================================================================="
print "DOUBLES: Strange results - using FB CVD()..."
print "==============================================================================="
' 0 1 2 3 4 5 6
' 1234567890123456789012345678901234567890123456789012345678901234
' SeeeeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
u64 = &b0111111111110111111111111111111111111111111111111111111111111111: Check_Bits_Dbl(d,u64)
u64 = &b0111111111110010101010101010101010101010101010101010101010101010: Check_Bits_Dbl(d,u64)
u64 = &b1111111111110111111111111111111111111111111111111111111111111111: Check_Bits_Dbl(d,u64)
u64 = &b1111111111110010101010101010101010101010101010101010101010101010: Check_Bits_Dbl(d,u64)
print "==============================================================================="
print "DOUBLES: Strange results - using FB and ASM..."
print "==============================================================================="
u64 = &b0111111111110111111111111111111111111111111111111111111111111111: Do_Asm_Dbl(u64,d)
u64 = &b0111111111110010101010101010101010101010101010101010101010101010: Do_Asm_Dbl(u64,d)
u64 = &b1111111111110111111111111111111111111111111111111111111111111111: Do_Asm_Dbl(u64,d)
u64 = &b1111111111110010101010101010101010101010101010101010101010101010: Do_Asm_Dbl(u64,d)
print "==============================================================================="
print "SINGLES (Few ordinary Values)..."
print "==============================================================================="
u32 = &h449a522b: Check_Bits_Sgl(s,u32) 'Value: 1234.5678
u32 = &h7f800000: Check_Bits_Sgl(s,u32) 'Value: -1/0
print "==============================================================================="
print "SINGLES: Strange results - using FB CVS()..."
print "==============================================================================="
' 0 1 2 3
' 12345678901234567890123456789012
' SeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMM
u32 = &b01111111101111111111111111111111: Check_Bits_Sgl(s,u32)
u32 = &b01111111100101010101010101010101: Check_Bits_Sgl(s,u32)
u32 = &b11111111101111111111111111111111: Check_Bits_Sgl(s,u32)
u32 = &b11111111100101010101010101010101: Check_Bits_Sgl(s,u32)
print "==============================================================================="
print "SINGLES: Strange results - using FB and ASM..."
print "==============================================================================="
u32 = &b01111111101111111111111111111111: Do_Asm_Sgl(u32,s)
u32 = &b01111111100101010101010101010101: Do_Asm_Sgl(u32,s)
u32 = &b11111111101111111111111111111111: Do_Asm_Sgl(u32,s)
u32 = &b11111111100101010101010101010101: Do_Asm_Sgl(u32,s)
print "[Press any key]..."
sleep
end 0
'***********************************************************************************
'The FP stack has 7 * 80-bit entries (ST[n])
Sub Do_Asm_Sgl(ByRef i as ulong, ByRef s as single)
Dim as ulong u32
u32 = i
asm fld dword ptr[i] 'load floating-point value, convert to 80-bit real, save into the FP stack.
asm fstp dword ptr[s] 'Pop the FP value from the FP stack, convert to 32-bit Real/FP, and save it in the stated 32-bit FP variable
Check_Bits_Sgl(s,u32)
End Sub
Sub Do_Asm_Dbl(ByRef i as ulongint, ByRef d as double)
Dim as ulongint u64
u64 = i
asm fld qword ptr[i] 'load floating-point value, convert to 80-bit real, save into the FP stack.
asm fstp qword ptr[d] 'Pop the FP value from the FP stack, convert to 64-bit Real/FP, and save it in the stated 64-bit FP variable
Check_Bits_Dbl(d,u64)
End Sub
'***********************************************************************************
sub Check_Bits_Dbl(byref d as double, byref u64 as ulongint)
Dim as string z
dim as ulong u1 = any '32-bit
dim as ulong u2 = any '32-bit
dim as ulongint u3 '64-bit
Dim as ulongint ex_s1, mn_s1, ex_v1, ex_f1, mn_v1, ex_s2, mn_s2, ex_v2, ex_f2, mn_v2
dim as integer i
z = MKLongInt(u64)
d = CVD(z) '?????????????????????????? Suspect (sometimes!)
print " Value ="; d; " ";: print format(d ,"0.000000000000000e+0000")
print "Incoming bits: ";hex(u64,16)
print "String, from MKLongInt(): ";: for i = 8 to 1 step -1: print hex(asc(mid(z,i,1)));: next i: print
print "Double, from CVD(): "; d; " ";: print format(d ,"0.000000000000000e+0000")
print "Convert DOUBLE back to bits: ";
u1 = cast( ulong ptr, @d )[0] '[0] = Lo-order 4 bytes, first 4 bytes in memory
u2 = cast( ulong ptr, @d )[1] '[1] = Hi-order 4 bytes, next 4 bytes in memory
u3 = u2 'Combined, 8 bytes, 64-bit calcs
u3 = u3 * 65536 * 65536
u3 = u3 + u1
if u64 = u3 then
print "Bits are Matching [OK]"
else
' If the Exp-Sign is unchanged, and
' if the Exponent is unchanged and all "1"s, and
' if the Mantissa sign has gone from 0 to 1, and
' if the mantissa is unchanged and non-zero, then
' this behaviour seems to be normal! So, check for this condition and don't treat as an error/bug.
' SeeeeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
ex_s1 = (u64 and &b1000000000000000000000000000000000000000000000000000000000000000) 'Exp-sign
ex_v1 = (u64 and &b0111111111110000000000000000000000000000000000000000000000000000) 'Exp-Value (non-zero?)
ex_f1 = (ex_v1 = &b0111111111110000000000000000000000000000000000000000000000000000) 'Exp-Value = FFF?
mn_s1 = (u64 and &b0000000000001000000000000000000000000000000000000000000000000000) 'Mant-Sign
mn_v1 = (u64 and &b0000000000000111111111111111111111111111111111111111111111111111) 'Mant-Value (EXCLUDES the SIGN!, non-zero?)
' SeeeeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMMM
ex_s2 = (u3 and &b1000000000000000000000000000000000000000000000000000000000000000) 'Exp-sign
ex_v2 = (u3 and &b0111111111110000000000000000000000000000000000000000000000000000) 'Exp-Value (non-zero?)
ex_f2 = (ex_v2 = &b0111111111110000000000000000000000000000000000000000000000000000) 'Exp-Value = FFF?
mn_s2 = (u3 and &b0000000000001000000000000000000000000000000000000000000000000000) 'Mant-Sign
mn_v2 = (u3 and &b0000000000000111111111111111111111111111111111111111111111111111) 'Mant-Value (EXCLUDES the SIGN!, non-zero?)
If Show_Oddball <> "Y" and _
ex_s1 = ex_s2 and _
ex_v1 = ex_v2 and ex_f1 <> 0 and ex_f2 <> 0 and _
mn_s1 = 0 and mn_s2 <> 0 and _
mn_v1 = mn_v2 and mn_v1 <> 0 and mn_v2 <> 0 Then 'Treat as OK!
print "Bits NOT Matching - but OK!!: bits[+] = "; hex(u3,16);" ";u3
else
print "Bits NOT Matching (??????????????????):"
print " bits[0]: ";hex(u1,16);" ";u1
print " bits[1]: ";hex(u2,16);" ";u2
print " bits[+]: ";hex(u3,16);" ";u3
endif
endif
Print "MJK-Macros>: INF="; is_INF_Dbl(d); " QNAN="; is_QNAN_Dbl(d); " SNAN="; is_SNAN_Dbl(d); " Num="; is_FP_Dbl(d)
print
End Sub
'***********************************************************************************
sub Check_Bits_Sgl(byref s as single, byref u32 as ulong)
Dim as ulong ui = any '32-bit
Dim as ulong ex_s1, mn_s1, ex_v1, ex_f1, mn_v1, ex_s2, mn_s2, ex_v2, ex_f2, mn_v2
Dim as string z
Dim as integer i
z = MKI(u32)
s = CVS(z) '?????????????????????????? Suspect (sometimes!)
print " Value ="; s; " ";: print format(s ,"0.000000000000000e+0000")
print "Incoming bits: ";hex(u32,8)
print "String, from MKI(): ";: for i = 4 to 1 step -1: print hex(asc(mid(z,i,1)));: next i: print
print "Single, from CVS(): "; s; " ";: print format(s ,"0.000000000000000e+0000")
print "Convert SINGLE back to bits: ";
ui = cast( ulong ptr, @s )[0] '[0] = Lo-order 4 bytes, first 4 bytes in memory
if ui = u32 then
print "Bits are Matching [OK]"
else
' SeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMM
ex_s1 = (u32 and &b10000000000000000000000000000000) 'Exp-sign
ex_v1 = (u32 and &b01111111100000000000000000000000) 'Exp-Value (non-zero?)
ex_f1 = (ex_v1 = &b01111111100000000000000000000000) 'Exp-Value = FFF?
mn_s1 = (u32 and &b00000000010000000000000000000000) 'Mant-Sign
mn_v1 = (u32 and &b00000000001111111111111111111111) 'Mant-Value (EXCLUDES the SIGN!, non-zero?)
' SeeeeeeeeMMMMMMMMMMMMMMMMMMMMMMM
ex_s2 = (ui and &b10000000000000000000000000000000) 'Exp-sign
ex_v2 = (ui and &b01111111100000000000000000000000) 'Exp-Value (non-zero?)
ex_f2 = (ex_v2 = &b01111111100000000000000000000000) 'Exp-Value = FFF?
mn_s2 = (ui and &b00000000010000000000000000000000) 'Mant-Sign
mn_v2 = (ui and &b00000000001111111111111111111111) 'Mant-Value (EXCLUDES the SIGN!, non-zero?)
If Show_Oddball <> "Y" and _
ex_s1 = ex_s2 and _
ex_v1 = ex_v2 and ex_f1 <> 0 and ex_f2 <> 0 and _
mn_s1 = 0 and mn_s2 <> 0 and _
mn_v1 = mn_v2 and mn_v1 <> 0 and mn_v2 <> 0 Then 'Treat as OK!
print "Bits NOT Matching - but OK!!: bits[0] = ";hex(ui,8);" ";ui
else
print "Bits NOT Matching (?????????????????????????????): bits[0] = ";hex(ui,8);" ";ui
endif
endif
Print "MJK-Macros>: INF="; is_INF_Sgl(s); " QNAN="; is_QNAN_Sgl(s); " SNAN="; is_SNAN_Sgl(s); " Num="; is_FP_Sgl(s)
print
End Sub
...just wanted to alert folks...