
The Precision Problem with Floating-Point Numbers
Floating-point numbers are typically represented using the IEEE 754 standard. In this format, a floating-point number is divided into three parts: a sign bit, an exponent, and a fraction (or significant). This representation allows a wide range of values, but not all decimal numbers can be expressed exactly in binary.
For example, the decimal number 0.1
cannot be precisely represented as a binary floating-point number. Instead, it is stored as an approximation:
0.1 (decimal) ≈ 0.0001100110011001100110011001100110011...(binary repeating)
This repeating binary pattern is truncated to fit into the finite bits allocated by the IEEE 754 format (e.g., 64 bits for double
). As a result, the stored value is slightly off from the exact value of 0.1
, introducing a rounding error.
Below is a simplified diagram of a 64-bit IEEE 754 floating-point number:
| Sign (1 bit) | Exponent (11 bits) | Fraction (52 bits) |
These small inaccuracies become apparent when performing arithmetic operations, especially when they accumulate over many calculations.
Alternatives
To avoid precision issues caused by floating-point arithmetic, consider the following common alternatives:
-
Use integers to represent fixed-point values: store it as an integer. For example, store
$10.23
as1023
cents.BigInts
andint64
are helpful in this approach. -
Use third-party libraries that implement decimal arithmetic:
-
JavaScript: Use
Decimal.js
orDinero.js
for precise calculations. -
Python: Use the built-in
decimal.Decimal
module for accurate decimal handling. -
Go: Use
shopspring/decimal
as alternative.
-
-
Use fixed-point decimal types provided by some languages: Some languages offer native support for fixed-point decimal types that ensure precision in decimal arithmetic.
- C# / .NET: Use the
decimal
type, which is designed specifically for financial and monetary calculations.
- C# / .NET: Use the
-
Use precise types in databases: When storing monetary or precision-sensitive data in a database, use
DECIMAL(p, s)
orNUMERIC(p, s)
types instead of floating-point types likeFLOAT
orDOUBLE
. These types maintain exact decimal representations and are supported in PostgreSQL, MySQL, and other relational databases.