0

If I have two arbitrary double precision floating point numbers A and B, where A is <= B, is there a way to determine whether the range A to B can be divided into N evenly spread (ignoring rounding errors) double precision floating point numbers between A and B that are distinct and respect strict total < ordering, with the value of each step being A+(B - A)/(N+1)*X where X = [1...N]? Example:

A=0
B=1
N=5

Result: [0, 1/6, 2/6, 3/6, 4/6, 5/6, 1]

In this case it's obvious that each of these numbers "fits" and we don't have to worry about loss of precision / rounding errors causing < ordering to be violated. But if A=0 and B=0.000000000001 it's far less obvious that this is "safe", since even if there is enough "space" to represent N additional values between A and B, it's not clear if rounding errors in the calculation of A+(B - A)/(N+1)*X could result in values that do not respect strict total < ordering.

I'm aware of "What Every Computer Scientist Should Know About Floating-Point Arithmetic", but it's particularly dense and hard to transform into higher level takeaways like this. I'm hoping for a robust answer, but am willing to concede with a "practical" answer, e.g. maybe I should just ensure that (B-A)/N is always greater than some threshold like 0.01.

  • There is C++ code [here](https://stackoverflow.com/a/56213511/298225) to compute how many representable values are between two values (for `float`, easily adaptable for other types). The `Distance` function counts one endpoint, so if `Distance(A, B)` is `N`+1 or greater, there are at least `N` representable values strictly between `A` and `B`. Whether there is a set of `N` of those values that is “(roughly) evenly spread” depends on your definition of “(roughly) evenly spread.” – Eric Postpischil Jun 29 '23 at 10:19
  • if B > A >= 0 and you want something of the form B - A > N * k, and N is representable in the number of bits of the mantissa, then using k = std::nextafter(A, B) - A should be fine. – lijie Jun 29 '23 at 10:37
  • I've edited the original question to clarify the evenly spread aspect. I suppose what I'm really trying to get at is how can I quantify the error bounds of the A+(B - A)/(N+1)*X calculation and provide a guarantee that with starting points A, B and N, the result will always respect strict total ordering (i.e. no two values will be equal, and each subsequent value is greater than the previous value)? – Daniel Resnick Jun 29 '23 at 21:11

1 Answers1

0

Assuming A and B are non-negative and finite, you can probably (ab)use the totalOrder predicate[*] to determine if there are at least N distinct representations in (A, B):

bit_cast_to_int(max(A, B)) - bit_cast_to_int(min(A, B)) > N.

if A and B are just finite, then probably calculate the positive and negative parts separately, and take care not to double count -0 and 0.

[*]: Finite values with the same sign are "dense" in their bit representation.

lijie
  • 4,811
  • 22
  • 26