Programmers might know this question: Can I use a float
variable for that? Or should I use double
or some integer? During my time as a programmer I came across this question on a few occasions. Usually I wanted to use floats for coordinates, like the x, y and z position of an object in space.
But floats have a problem: The larger the number becomes the larger the gap between two representable floats. For example the next representable float
after 512.0 is 512.000061. So the gap between the two numbers is 0.000061. After 65536 the next representable number is 65536.007812 so the gap is 0.007812 large. A float
variable simply can't represent anything between any of those two values. It doesn't have enough bits to do so. This is also called the precision of the float: The higher the value the lower the precision.
Some time ago I used float
s for the x and y coordinates of a large map with mostly images on it. But I was wondering how large that map (that is the x or y coordinate) can become before before the gap between two float values is larger than one pixel (1.0). If a coordinate exceeds this value I can no longer properly position images on the map and can no longer use floats
to calculate the position of individual pixels.
Usually I would guess based on what I read and picked up over the years. But this time I wrote a small C program that prints a table of float values and the size of the gap to the next larger value.
#include <stdio.h>
#include <math.h>
int main() {
printf("float:\n");
for (float x = 1.0f, precision; precision < 1.0f; x *= 2.0f) {
precision = nextafterf(x, INFINITY) - x;
printf("precision of %f at value %.0f\n", precision, x);
}
printf("\ndouble:\n");
for (double x = 1.0, precision; precision < 1.0; x *= 2.0) {
precision = nextafter(x, INFINITY) - x;
printf("precision of %lf at value %.0lf\n", precision, x);
}
return 0;
}
It uses the nextafter() function of C99 and for completenesses sake I also added a table for double
. You can compile it with gcc -std=c99 float_precision_table.c -lm
.
This is a bit of the programs output:
float:
…
precision of 0.003906 at value 32768
precision of 0.007812 at value 65536
precision of 0.015625 at value 131072
precision of 0.031250 at value 262144
precision of 0.062500 at value 524288
precision of 0.125000 at value 1048576
precision of 0.250000 at value 2097152
precision of 0.500000 at value 4194304
precision of 1.000000 at value 8388608
At the float
value of about 8388608
the gaps are about 1.0
in size. So once the x or y coordinate exceeds this value strange errors will happen in my program. Fortunately this value is quite a bit larger than I expected it to be.
Even if I would use float
for coordinates in a 3D world and wanted 1cm precision the world can reach from about -65536m to about +65536m in each direction. That's a cube with a side length of about 130km. Which is again way larger than I originally thought. :)
As a little contrast here are some values for double
s:
double:
…
precision of 0.007812 at value 35184372088832
precision of 0.015625 at value 70368744177664
precision of 0.031250 at value 140737488355328
precision of 0.062500 at value 281474976710656
precision of 0.125000 at value 562949953421312
precision of 0.250000 at value 1125899906842624
precision of 0.500000 at value 2251799813685248
precision of 1.000000 at value 4503599627370496
You can make some quite large worlds with double
coordinates. In the same situation as above it would be a cube with a side length of 470 AU and still something like 1cm precision at the outer regions. :)
I hope this small program can provide some point of reference should you ever find yourself pondering the same questions.