A binary floating-point format such as IEEE-754 can be thought of as consisting of a number of binades. A binade is a complete set of significand values, all with the same power-of-two exponent. So the half-open interval [1.0, 2.0) is one binade, as is [2.0, 4.0), as is [4.0, 8.0).
For double precision, each binade consists of 252 significand values.
So to compute the number of values between R0 and R1, you can do that in three parts:
- number of values between R0 and the next power of two greater than R0 (call this next power-of-two value x)
- number of values between R1 and the previous power of two less than R1 (call this previous power-of-two value y)
- number of values in full binades between x and y
The number of values between R0 and x is (x - R0) / res1, where res1 is the resolution in the binade containing R0, which is epsilon times the previous power of two less than R0.
The number of values between R1 and y is (R1 - y) / res2, where res2 is the resolution in the binade containing R1, which is epsilon times y.
And then part 3 is 252 times the number of binades, and the number of binades is one less than the number of exact powers of two between R0 and R1.
For example, if R0 is 12.34 and R1 is 345.678, the powers of 2 between R0 and R1 are 16, 32, 64, 128, and 256. There are 5 of them, so there are 4 full binades. x is 16, and y is 256.
The "epsilon" I referred to is a property of the floating point format, and is (by definition) the resolution of the binade [1.0, 2.0). For double precision, epsilon is 2.22045e-16.
There are obviously still a fair number of details to get right, and some edge cases — in particular, the cases where there are one or zero powers of two between R0 and R1. But this should get you started.
union
. – Catacaustic