Floating-Point Numbers
float and double store numbers with fractional parts using binary floating point. They cover an enormous range, but most decimal fractions can only be stored approximately — so you need to know how to print them, compare them and when not to use them.
float and double
#include <stdio.h> int main(void) { float f = 3.14159265358979f; double d = 3.14159265358979; printf("float: %.15f\n", f); printf("double: %.15f\n", d); return 0; }
float: 3.141592741012573 double: 3.141592653589790
A float keeps about 7 significant digits; a double about 15–16. The f suffix makes a float literal — without it, 3.14 is a double. Use double unless you have a reason not to (large arrays, graphics, embedded hardware).
Approximate by nature
Just as 1/3 can't be written exactly in decimal, 0.1 can't be written exactly in binary. Small errors appear:
#include <stdio.h> int main(void) { double a = 0.1 + 0.2; printf("%.17f\n", a); printf("%s\n", a == 0.3 ? "equal" : "not equal"); return 0; }
0.30000000000000004 not equal
Never compare floating-point results with ==. Check whether they're close enough instead:
#include <stdio.h> #include <math.h> #include <stdbool.h> bool nearly_equal(double x, double y) { return fabs(x - y) <= 1e-9 * fmax(1.0, fmax(fabs(x), fabs(y))); } int main(void) { printf("%d\n", nearly_equal(0.1 + 0.2, 0.3)); return 0; }
1
The tolerance depends on your problem; this one scales with the size of the numbers.
Money: use integers
Because of rounding, don't store money in double. Count the smallest unit — cents — in an integer, and only format it as a decimal when printing:
#include <stdio.h> int main(void) { long long price_cents = 1999; int quantity = 3; long long total = price_cents * quantity; printf("Total: %lld.%02lld\n", total / 100, total % 100); return 0; }
Total: 59.97
Printing
| Specifier | Output for 1234.5678 |
|---|---|
%f | 1234.567800 (6 decimals by default) |
%.2f | 1234.57 (rounded) |
%e | 1.234568e+03 (scientific) |
%g | 1234.57 (shortest sensible form) |
%f prints both float and double. (For scanf it's different: %f reads a float and %lf a double — lesson 15.)
#include <stdio.h> int main(void) { double x = 1234.5678; printf("%f | %.2f | %e | %g\n", x, x, x, x); printf("%g | %g\n", 0.00001234, 123456789.0); return 0; }
1234.567800 | 1234.57 | 1.234568e+03 | 1234.57 1.234e-05 | 1.23457e+08
Special values
Floating point has values for results that aren't ordinary numbers: infinity and "not a number" (NaN).
#include <stdio.h> #include <math.h> int main(void) { double big = 1e308 * 10; double nothing = sqrt(-1.0); printf("%f %f\n", big, -big); printf("%f\n", nothing); printf("isinf: %d, isnan: %d\n", isinf(big), isnan(nothing)); printf("NaN == NaN? %d\n", nothing == nothing); return 0; }
inf -inf nan isinf: 1, isnan: 1 NaN == NaN? 0
A NaN isn't equal to anything, not even itself; test for it with isnan. (Integer division by zero, by contrast, is undefined behaviour and usually crashes.)
Limits
#include <stdio.h> #include <float.h> int main(void) { printf("double: about %d digits, max %g\n", DBL_DIG, DBL_MAX); printf("float: about %d digits, max %g\n", FLT_DIG, FLT_MAX); printf("smallest step after 1.0: %g\n", DBL_EPSILON); return 0; }
double: about 15 digits, max 1.79769e+308 float: about 6 digits, max 3.40282e+38 smallest step after 1.0: 2.22045e-16
Try it yourself
Add 0.1 to a double ten times and print the result with 17 decimals. Is it exactly 1? Then do the same with integers counting tenths.
0.99999999999999989 1.0