-
Notifications
You must be signed in to change notification settings - Fork 0
ArbitraryPrecisionFloatTests
ArbitraryPrecisionFloatTests is a SUnit TestCase for ArbitraryPrecisionFloat.
Implementation details of the tests are not yet documented. SUnit tests are expected to be readable and auto-documented, however, some details might deserve further explanations.
For example, for testing function f accuracy with precision p, one simple way is to check against some other library, for example versus Smalltalk Float:
x_arbit := someValue asArbitraryPrecisionFloatNumBits: Float precision.
x_float := x_arbit asFloat.
f_arbit := x_arbit perform: f.
f_float := x_float perform: f.
self assert: f_arbit = f_float.
But this generally just asserts that the Float functions are not correctly rounded. First because libm is generally not correctly rounded, and second because most Smalltalk implementations are not even using libm - like tan being implemented as ^self sin/self cos
, or worse, cos implemented as ^ (self + Halfpi) sin
...
Another way is self testing with an extended precision: we use higher precision, and check that it leads to the same rounding.
x_single := someValue asArbitraryPrecisionFloatNumBits: p.
x_double := x_single asArbitraryPrecisionFloatNumBits: 2*p.
f_single := x_single perform: f.
f_double := x_double perform: f.
self assert: (f_double asArbitraryPrecisionFloatNumBits: p) = f_single.
But such test is subject to DoubleRoundingProblem and must be handled with care. In case of exact tie, we can for example retry with quadruple precision.
Another possibility is to use a power serie expansion using exact arithmetic (using infinite precision of Integer and Fraction) up to a reasonnable length (for example when new terms are several binades below the ulp), then perform a single rounding operation. For example, testing exp(x) at precision p.
f := x asFraction.
term := 1.
sum := 1.
n := 1.
[term := term * f / n.
n := n + 1.
sum := sum + term.
term abs * (2 raisedTo: 2*p) > sum]
whileTrue.
error := (x exp asFraction - sum) abs.
self assert: error < (x exp ulp / 2)
In any case, testing that the implementation will allways round correctly whatever x value is another problem. Even with low precision this cannot be achieved by exhaustive tests, because the exponent are unbounded.