The answer to phoog is good, but it has weaknesses with negative numbers, max_double, infinity, and NaN.
phoog_ULP (positive x) -> positive number. Good.
phoog_ULP (negative x) -> negative number. I would expect a positive number.
To fix this, I recommend instead:
long bits = BitConverter.DoubleToInt64Bits(value) & 0x7FFFFFFFFFFFFFFFL;
Below are additional cases requiring permission if you need ...
phoog_ULP (x = +/- Max_double 1.797 ... e + 308) returns an infinite result. (+ 1,996 ... e + 292).
phoog_ULP (x = +/- Infinity) leads to NaN. + Expected infinity.
phoog_ULP (x = +/- NaN) may unexpectedly change from sNan to qNaN. No changes are expected. You can argue in any case, if the sign should become + in this case.
To solve this problem, I see only a short series of brutal if () tests to place them, possibly by the value of βbitsβ for expediency. Example:
double ulpc(double value) { long long bits = BitConverter::DoubleToInt64Bits(value); if ((bits & 0x7FF0000000000000L) == 0x7FF0000000000000L) { // if x is not finite if (bits & 0x000FFFFFFFFFFFFFL) { // if x is a NaN return value; // I did not force the sign bit here with NaNs. } return BitConverter.Int64BitsToDouble(0x7FF0000000000000L); // Positive Infinity; } bits &= 0x7FFFFFFFFFFFFFFFL; // make positive if (bits == 0x7FEFFFFFFFFFFFFL) { // if x == max_double (notice the _E_) return BitConverter.Int64BitsToDouble(bits) - BitConverter.Int64BitsToDouble(bits - 1); } double nextValue = BitConverter.Int64BitsToDouble(bits + 1); double result = nextValue - value; }
chux source share