Testcode gebaut! Leider vergleicht der noch nicht sauber.
hier der Link zum Vorgänger-Thread
https://www.purebasic.fr/german/viewtopic.php?t=33098
TestCode für nearlyEqual
Code: Alles auswählen
EnableExplicit
Procedure.d _CalcSinglePrecision()
Protected.f FPr, s
; IT CARRIES OUT AN APPROXIMATION OF MACHINE PRECISION
FPr = 1.0
s = FPr + 1.0
While s > 1.0
FPr = 0.5 * FPr
s = FPr + 1.0
Wend
ProcedureReturn FPr * 2.0
EndProcedure
Global.f mem_Precsion_Single = _CalcSinglePrecision()
Debug "Presicion = " + StrF(mem_Precsion_Single,15)
Procedure.i nearlyEqual(A.f, B.f, Epsilon.f= 0.0000002)
Protected.f eps
; Protected *pA.Long = @A
; Protected *pB.Long = @B
; Debug "A = " + *pA\l
; Debug "B = " + *pB\l
If IsNAN(A) Or IsNAN(B)
ProcedureReturn #False
EndIf
If IsInfinity(A) Or IsInfinity(B)
ProcedureReturn #False
EndIf
If A=B
ProcedureReturn #True
ElseIf A > B
eps = A * mem_Precsion_Single
Else
eps = B * mem_Precsion_Single
EndIf
If Abs(A-B) < eps
ProcedureReturn #True
Else
ProcedureReturn #False
EndIf
EndProcedure
#MAX_VALUE = 3.4028235e38
#MIN_VALUE = 1.4e-45
; https://floating-point-gui.de/errors/comparison/
Procedure.i nearlyEqual_1(A.f, B.f, Epsilon.f=0.0000002)
Protected.f absA, absB, diff, absSum, min
absA = Abs(A)
absB = Abs(B)
diff = Abs(absA-absB)
absSum = absA + absB
If IsNAN(A) Or IsNAN(B)
ProcedureReturn #False
EndIf
If IsInfinity(A) Or IsInfinity(B)
ProcedureReturn #False
EndIf
If A=B
ProcedureReturn #True
ElseIf Bool (A=0.0) | Bool(B=0.0) | Bool(absSum < #MIN_VALUE)
; a Or b is zero Or both are extremely close To it
; relative error is less meaningful here
ProcedureReturn Bool(diff < (Epsilon * #MIN_VALUE))
Else ; use relative error
If absSum < #MAX_VALUE
ProcedureReturn Bool((diff / absSum) < epsilon)
Else
ProcedureReturn Bool((diff / #MAX_VALUE) < epsilon)
EndIf
EndIf
EndProcedure
Macro DoubleQuote
"
EndMacro
Macro assertTrue (Expression)
CompilerIf #PB_Compiler_Debugger ; ’ Assert ’ ( Erklärung ) nur im Debug - Modus aktivieren
If Not Expression
Debug "Error assertTrue ( Line " + #PB_Compiler_Line + " ) : " + DoubleQuote#Expression#DoubleQuote
EndIf
CompilerEndIf
EndMacro
Macro assertFalse (Expression)
CompilerIf #PB_Compiler_Debugger ; ’ Assert ’ ( Erklärung ) nur im Debug - Modus aktivieren
If Expression
Debug "Error assertFalse ( Line " + #PB_Compiler_Line + " ) : " + DoubleQuote#Expression#DoubleQuote
EndIf
CompilerEndIf
EndMacro
;https://floating-point-gui.de/errors/NearlyEqualsTest.java
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Regular large numbers - generally Not problematic"
assertTrue(nearlyEqual(1000000, 1000001))
assertTrue(nearlyEqual(1000001, 1000000))
assertFalse(nearlyEqual(10000, 10001))
assertFalse(nearlyEqual(10001, 10000))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Negative large numbers"
assertTrue(nearlyEqual(-1000000, -1000001))
assertTrue(nearlyEqual(-1000001, -1000000))
assertFalse(nearlyEqual(-10000, -10001))
assertFalse(nearlyEqual(-10001, -10000))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Numbers around 1"
assertTrue(nearlyEqual(1.0000001, 1.0000002))
assertTrue(nearlyEqual(1.0000002, 1.0000001))
assertFalse(nearlyEqual(1.0002, 1.0001))
assertFalse(nearlyEqual(1.0001, 1.0002))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Numbers around -1"
assertTrue(nearlyEqual(-1.000001, -1.000002))
assertTrue(nearlyEqual(-1.000002, -1.000001))
assertFalse(nearlyEqual(-1.0001, -1.0002))
assertFalse(nearlyEqual(-1.0002, -1.0001))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Numbers between 1 And 0"
assertTrue(nearlyEqual(0.000000001000001, 0.000000001000002))
assertTrue(nearlyEqual(0.000000001000002, 0.000000001000001))
assertFalse(nearlyEqual(0.000000000001002, 0.000000000001001))
assertFalse(nearlyEqual(0.000000000001001, 0.000000000001002))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Numbers between -1 And 0"
assertTrue(nearlyEqual(-0.000000001000001, -0.000000001000002))
assertTrue(nearlyEqual(-0.000000001000002, -0.000000001000001))
assertFalse(nearlyEqual(-0.000000000001002, -0.000000000001001))
assertFalse(nearlyEqual(-0.000000000001001, -0.000000000001002))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Small differences away from zero"
assertTrue(nearlyEqual(0.3, 0.30000003))
assertTrue(nearlyEqual(-0.3, -0.30000003))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Comparisons involving zero"
assertTrue(nearlyEqual(0.0, 0.0))
assertTrue(nearlyEqual(0.0, -0.0))
assertTrue(nearlyEqual(-0.0, -0.0))
assertFalse(nearlyEqual(0.00000001, 0.0))
assertFalse(nearlyEqual(0.0, 0.00000001))
assertFalse(nearlyEqual(-0.00000001, 0.0))
assertFalse(nearlyEqual(0.0, -0.00000001))
assertTrue(nearlyEqual(0.0, 1e-40, 0.01))
assertTrue(nearlyEqual(1e-40, 0.0, 0.01))
assertFalse(nearlyEqual(1e-40, 0.0, 0.000001))
assertFalse(nearlyEqual(0.0, 1e-40, 0.000001))
assertTrue(nearlyEqual(0.0, -1e-40, 0.1))
assertTrue(nearlyEqual(-1e-40, 0.0, 0.1))
assertFalse(nearlyEqual(-1e-40, 0.0, 0.00000001))
assertFalse(nearlyEqual(0.0, -1e-40, 0.00000001))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Comparisons involving extreme values (overflow potential)"
assertTrue(nearlyEqual(#MAX_VALUE, #MAX_VALUE))
assertFalse(nearlyEqual(#MAX_VALUE, -#MAX_VALUE))
assertFalse(nearlyEqual(-#MAX_VALUE, #MAX_VALUE))
assertFalse(nearlyEqual(#MAX_VALUE, #MAX_VALUE / 2))
assertFalse(nearlyEqual(#MAX_VALUE, -#MAX_VALUE / 2))
assertFalse(nearlyEqual(-#MAX_VALUE, #MAX_VALUE / 2))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Comparisons involving infinities"
assertFalse(nearlyEqual(Infinity(), Infinity()))
assertFalse(nearlyEqual(-Infinity(), -Infinity()))
assertFalse(nearlyEqual(-Infinity(), Infinity()))
assertFalse(nearlyEqual(Infinity(), #MAX_VALUE))
assertFalse(nearlyEqual(-Infinity(), -#MAX_VALUE))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Comparisons involving NaN values"
assertFalse(nearlyEqual( NaN(), NaN()))
assertFalse(nearlyEqual( NaN(), 0.0))
assertFalse(nearlyEqual(-0.0, NaN()))
assertFalse(nearlyEqual( NaN(), -0.0))
assertFalse(nearlyEqual(0.0, NaN()))
assertFalse(nearlyEqual( NaN(), Infinity()))
assertFalse(nearlyEqual(Infinity(), NaN()))
assertFalse(nearlyEqual( NaN(), -Infinity()))
assertFalse(nearlyEqual(-Infinity(), NaN()))
assertFalse(nearlyEqual( NaN(), #MAX_VALUE))
assertFalse(nearlyEqual(#MAX_VALUE, NaN()))
assertFalse(nearlyEqual( NaN(), -#MAX_VALUE))
assertFalse(nearlyEqual(-#MAX_VALUE, NaN()))
assertFalse(nearlyEqual( NaN(), #MIN_VALUE))
assertFalse(nearlyEqual(#MIN_VALUE, NaN()))
assertFalse(nearlyEqual( NaN(), -#MIN_VALUE))
assertFalse(nearlyEqual(-#MIN_VALUE, NaN()))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : Comparisons of numbers on opposite sides of 0"
assertFalse(nearlyEqual(1.000000001, -1.0))
assertFalse(nearlyEqual(-1.0, 1.000000001))
assertFalse(nearlyEqual(-1.000000001, 1.0))
assertFalse(nearlyEqual(1.0, -1.000000001))
assertTrue(nearlyEqual(10 * #MIN_VALUE, 10 * -#MIN_VALUE))
assertFalse(nearlyEqual(10000 * #MIN_VALUE, 10000 * -#MIN_VALUE))
Debug " "
Debug "Line : " + #PB_Compiler_Line + " : The really tricky part - comparisons of numbers very close To zero."
assertTrue(nearlyEqual(#MIN_VALUE, #MIN_VALUE))
assertTrue(nearlyEqual(#MIN_VALUE, -#MIN_VALUE))
assertTrue(nearlyEqual(-#MIN_VALUE, #MIN_VALUE))
assertTrue(nearlyEqual(#MIN_VALUE, 0))
assertTrue(nearlyEqual(0, #MIN_VALUE))
assertTrue(nearlyEqual(-#MIN_VALUE, 0))
assertTrue(nearlyEqual(0, -#MIN_VALUE))
assertFalse(nearlyEqual(0.000000001, -#MIN_VALUE))
assertFalse(nearlyEqual(0.000000001, #MIN_VALUE))
assertFalse(nearlyEqual(#MIN_VALUE, 0.000000001))
assertFalse(nearlyEqual(-#MIN_VALUE, 0.000000001))