1
votes

From ULP Wikipedia's page:

Another definition, suggested by John Harrison, is slightly different: ULP(x) is the distance between the two closest straddling floating-point numbers a and b (i.e., those with a ≤ x ≤ b and a ≠ b), assuming that the exponent range is not upper-bounded.

From IEEE 754 2008:

2.1.44 quantum: The quantum of a finite floating-point representation is the value of a unit in the last position of its significand. This is equal to the radix raised to the exponent q, which is used when the significand is regarded as an integer.

Question: What is the difference between ULP (John Harrison's definition) and quantum (from IEEE 754)?

Do I understand right that quantum of double x can be computed as:

double ulp(double x)
{
        int exp;
        frexp( x, &exp );
        return ldexp( 0.5, exp-52 );
}
double quantum(double x)
{
        int exp;
        return ulp(frexp( x, &exp ));
}
1
The IEEE-754 definition applies only to floating-point numbers (the real numbers that are representable in the floating-point format); it does not provide a definition for real numbers between floating-point numbers.Eric Postpischil

1 Answers

1
votes

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.