What is the difference between ULP (John Harrison's definition) and quantum (from IEEE 754)?
[edit]
OP's quantum()
appears incorrect, consistently returning 1.11022e-16
for all finite x
, even when x
is a sub-normal.
Rest of answer assumes quantum()
is more like quantum_alt()
below which has the same result for each [power-of-2 ... 2*power-of-2). Note the [)
.
Power of the radix
When x
is a power-of-the-base These definitions differ only at signed powers of the radix
For binary64, consider when x
is a power-of-2. The next larger FP value is x + u
and the next smaller value is x - u/2
.
John Harrison: "distance between the two closest straddling floating-point numbers a and b (i.e., those with a ≤ x ≤ b and a ≠ b)" implies a
is the smaller value and x == b
and ULP is u/2
.1
Quantum: "representation is the value of a unit in the last position of its significand" implies the ULP
is u
.
The distance b-a
is 1/2 the "quantum" definition; a
being in the smaller exponent subrange than x
and whose last position significant is half of x
.
Applicability
Definitions also differ in that both apply to floating point values, but not quantum with real values like 1/7, √2, π. @Eric Postpischil
Both OP functions are wrong in select cases.
ulp()
per John Harrison, is amiss when x
is a power-of-2, zero or a sub-normal.
Alternate
#include <math.h>
// Using the convention ULP(x) == ULP(-x)
// Adjust if you want a signed result.
double ulp_JH(double x) {
x = fabs(x);
if (isfinite(x)) {
double lower = nextafter(x, -1.0); // 1st FP number smaller than x
return x - lower;
}
return x; // NAN, infinity
}
OP's quantum()
is amiss when x
is a zero or a sub-normal.
double quantum_alt(double x) {
x = fabs(x);
if (x < DBL_MAX) {
double higher = nextafter(x, DBL_MAX); // 1st FP number larger than x
return higher - x;
}
if (isfinite(x)) {
double lower = nextafter(x, 0.0); // Special case for DBL_MAX
return x - lower;
}
return x; // NAN, infinity
}
1 Except when x == DBL_TRUE_MIN
. In that case. ULP(DBL_TRUE_MIN)
is DBL_TRUE_MIN
.