NextAfter, which returns the floating-point neighbor of its first argument in the direction of its second, produces values adjacent to the seam of the approximation:
void ArtfulTest(int testCount) {
const double kSeam = 0x1.0p-27;
double xDown = kSeam, xUp = kSeam;
for (int i = 0; i < testCount; i++) {
xDown = NextAfter(xDown, -kInfinity);
ArcTanhTest(xDown); // compare Sample... with SlowButSure...
xUp = NextAfter(xUp, +kInfinity);
ArcTanhTest(xUp);
}
}
Other functions help decompose a floating-point value into its exponent and significand without resorting to nonportable integer operations that depend on intimate details of the data formats. Here is a typical sequence applied to a double number:
double signSaver = CopySign(1.0, value);
value = Abs(value); // synonymous with CopySign(value, 1.0)
double powerOfTwo = Logb(value);
double significand = Scalb(value, (long) -powerOfTwo);
After this sequence, the following formula holds exactly for a finite, nonzero value: