What are floating-point numbers?

A floating-point type variable can hold numbers with fractional components, such as 9876.5, -12.75, or 0.00832. The "floating" refers to the decimal point's ability to support varying numbers of digits before and after it. Floating-point types are always signed.

Floating-point types in C++

C++ provides three fundamental floating-point types:

C++ Type Typical Size Precision
float 4 bytes 6-9 significant digits
double 8 bytes 15-18 significant digits
long double 8-16 bytes varies
Best Practice
Prefer double over float unless space is critical, as float's lack of precision often causes inaccuracies. Avoid long double as its behavior varies across platforms.

Declaring floating-point variables

float measurement{};
double distance{};

When using floating-point literals, always include a decimal place:

int whole{7};         // 7 is an integer
double decimal{7.0};  // 7.0 is a double
float precise{7.0f};  // 7.0f is a float (note the f suffix)

By default, floating-point literals are type double. Use the f suffix for float literals.

Understanding precision

Floating-point types can store only a limited number of significant digits. Additional digits are lost or represented imprecisely.

  • float: 6-9 digits of precision (typically 7)
  • double: 15-18 digits of precision (typically 16)
#include <iomanip>
#include <iostream>

int main()
{
    float number{987654321.0f};  // 10 significant digits
    std::cout << std::setprecision(9);
    std::cout << number << '\n';  // outputs 987654336

    return 0;
}

The value changed from 987654321 to 987654336 because float can't precisely store 10 significant digits. This precision loss is called a rounding error.

Rounding errors are everywhere

Even simple numbers like 0.1 can't be stored exactly in binary:

#include <iomanip>
#include <iostream>

int main()
{
    double value{0.1};
    std::cout << std::setprecision(17);
    std::cout << value << '\n';  // outputs 0.10000000000000001

    return 0;
}

Rounding errors accumulate with operations:

double result{0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1 + 0.1};
// result is 0.99999999999999989, not 1.0!
Key Concept
Rounding errors occur constantly with floating-point numbers - they're the norm, not the exception. Never assume floating-point numbers are exact, and avoid direct equality comparisons.

Special values: NaN and Inf

IEEE 754-compatible formats support special values:

  • Inf (infinity): Positive or negative
  • NaN ("Not a Number"): Result of mathematically invalid operations
  • Signed zero: +0.0 and -0.0
double zero{0.0};
double positiveInfinity{7.0 / zero};   // inf
double notANumber{zero / zero};         // nan
Best Practice
Avoid division by 0.0, even if your compiler supports it.

Summary

Two essential points about floating-point numbers:

  1. They're useful for storing very large or very small numbers, including those with fractional components
  2. They often have small rounding errors that can cause unexpected behavior in comparisons and accumulate during mathematical operations