We are currently working on new rules for what content should and shouldn't be allowed on this website, and are looking for feedback! See Esolang:2026 topicality proposal to view and give feedback on the current draft.
Arbitrary-Precision Floating Point Numbers
>>> 0.1 + 0.2 0.30000000000000004
This iconic scene is something that many people who do programming are probably familiar with.
This is an operation in the Python console. We want to add 0.1 and 0.2 together, but the result isn’t exactly 0.3—it comes out as this weird number instead.
Why 0.30000000000000004?
This is actually because CPUs aren't based on decimal, they're based on binary. In binary, it's really hard to represent decimal fractions exactly without repeating decimals, and since a CPU's capacity isn't infinite, the accuracy of numbers has to compromise with the CPU. This is why the actual numbers aren't perfectly precise.
In the example above, the calculation we're trying to perform is actually 0.1000000000000000055511151231257827021181583404541015625 + 0.200000000000000011102230246251565404236316680908203125, which equals 0.3000000000000000444089209850062616169452667236328125. So it's no wonder that the final number comes out as 0.30000000000000004.
Arbitrary-Precision Floating Point Numbers
But arbitrary-precision decimals are not only feasible in programming, they also have mature and widely used implementations in many mainstream languages. Its core idea is to split a number into two separate parts for storage and calculation:
- An arbitrary-length integer (the significant digits): this is the core numeric part of the number.
- An exponent (the decimal point position): used to indicate where the decimal point is within the significant digits.
For example, the number 123.45 can be represented as significant digits 12345 and exponent -2 (meaning the decimal point moves 2 places to the left), which is 12345×10-2.
Since the significant digits can be an integer of any length (limited only by computer memory), theoretically, it can represent decimals of any size and precision. All arithmetic operations (addition, subtraction, multiplication, division, etc.) are done by operating on these "big integers."
Implementations in Mainstream Languages
Almost all mainstream programming languages provide support for arbitrary-precision decimals either through standard libraries or popular third-party libraries.
- Python
- The
decimalmodule in the standard library. It fully implements the general decimal arithmetic specification, making it perfect for scenarios like finance that require precise calculations. - Java
- The
java.math.BigDecimalclass in the standard library. It consists of an arbitrary-precision integer (BigInteger) and a 32-bit integer scale, and it's immutable. - C/C++
- Can be done through third-party libraries, such as the high-precision computation library GNU MPFR or the decimal-focused libmpdec (which Python's
decimalmodule is based on). - JavaScript
- Since there's no native support, third-party libraries like
big.js,decimal.js, orbignumber.jsare commonly used. - Other languages
- .NET has the decimal type (128-bit, high precision but not arbitrary), and languages like PHP, Ruby, Rust, etc., also have corresponding library support.
Key Considerations in Implementation
When implementing arbitrary-precision decimals, you need to carefully handle several key points:
- Performance
- Since it involves complex operations on big integers, it's usually much slower than hardware-supported floating-point calculations. That's why high-performance implementations (like libmpdec) use optimized algorithms such as Karatsuba multiplication.
- Precision and Rounding
- You need to precisely control calculation accuracy and rounding methods. This is usually managed through a 'Context' object, for example, by setting a global precision of 100 decimal places.
- Special Values
- You need to support special values like +∞, -∞, NaN, as well as positive and negative zero (+0 and -0).
My First Thought on This Concept
At first, I (User:PrySigneToFry) thought I could do it using a dictionary (a container that specifically stores key-value pairs, which in other languages might correspond to a hash table or a map). I would set the keys as the digit position indexes (for example, "0" for the ones place, "1" for the tens place, "2" for the hundreds place, "3" for the thousands place, "-1" for the tenths place, etc.) and set the values as the integers corresponding to each place. But this method seemed a bit cumbersome, so in the end, this idea was put on hold at the concept stage.