Why Does 64 ** (1/3) Return 3.999999 Instead of 4 in Python?
Problem
When I calculated the cube root of 64 in Python, I got this unexpected result:
>>> 64 ** (1/3)3.9999999999999996I expected exactly 4, but Python returned 3.9999999999999996. At first glance, this looked like a bug. Is Python’s math broken?
Environment
- Python 3.11 (tested on 3.8+ as well)
- macOS and Linux
- Default Python REPL
What happened?
I was working on a simple math problem when I tried to calculate the cube root of 64:
# Simple cube root calculationresult = 64 ** (1/3)print(f"Cube root of 64: {result}")print(f"Is it equal to 4? {result == 4}")When I ran this code:
$ python cube_root_test.pyCube root of 64: 3.9999999999999996Is it equal to 4? FalseI was confused. The math says the cube root of 64 is exactly 4, so why is Python giving me this strange result?
Let me try a few more tests to understand what’s happening:
>>> 1/30.3333333333333333
>>> (1/3).hex()'0x1.5555555555555p-2'
>>> 0.1 + 0.20.30000000000000004I can see the pattern now. The fraction 1/3 is stored as 0.3333333333333333 (truncated), and the hex representation shows repeating 5s in binary. Even simple addition like 0.1 + 0.2 doesn’t give exactly 0.3.
How to solve it?
I tried several approaches to get the expected result.
Solution 1: Round the result
The simplest fix is to round the result to a reasonable number of decimal places:
result = round(64 ** (1/3), 10)print(result) # 4.0
# For comparison with 4print(result == 4) # TrueThis works for most display purposes and general calculations. The round() function returns 4.0, which compares equal to 4.
Solution 2: Use math.isclose() for comparisons
When comparing floating-point numbers, I should use math.isclose() instead of ==:
import math
result = 64 ** (1/3)print(math.isclose(result, 4)) # Trueprint(math.isclose(result, 4, rel_tol=1e-9)) # True with stricter toleranceThis checks if two numbers are close enough within a relative tolerance, which is the proper way to compare floats.
Solution 3: Use Decimal for exact precision
For applications requiring precise decimal arithmetic (like financial calculations), I can use the decimal module:
from decimal import Decimal, getcontext
# Set precision high enough for our calculationgetcontext().prec = 20
result = Decimal(64) ** (Decimal(1) / Decimal(3))print(result) # 3.9999999999999999999
# Or quantize to specific decimal placesresult_quantized = (Decimal(64) ** (Decimal(1) / Decimal(3))).quantize(Decimal('1.00'))print(result_quantized) # 4.00The Decimal module performs exact decimal arithmetic instead of binary floating-point, avoiding the 1/3 representation issue.
The reason
The core issue is that Python’s float type uses IEEE 754 double-precision binary floating-point format, which cannot exactly represent the fraction 1/3.
Here’s why:
-
In binary, 1/3 is a repeating fraction: Just like 1/3 = 0.333… in decimal, in binary it’s 0.0101010101… (repeating forever).
-
Limited precision: IEEE 754 doubles have 53 bits of precision, so the binary representation must be truncated.
-
Small errors compound: When I compute
64 ** (1/3), Python uses the truncated value of 1/3 (approximately 0.3333333333333333), not the exact fraction. -
The result is actually correct: The value 3.9999999999999996 is the closest IEEE 754 double-precision float to the true mathematical answer.
I can verify this isn’t just a Python problem:
// JavaScript consoleMath.pow(64, 1/3) // 3.9999999999999996// JavaMath.pow(64, 1.0/3) // 3.9999999999999996// C++pow(64, 1.0/3) // 3.9999999999999996All languages using IEEE 754 floating-point have the same behavior. This is a fundamental limitation of binary floating-point representation, not a Python bug.
Summary
In this post, I explained why 64 ** (1/3) returns 3.9999999999999996 instead of exactly 4 in Python. The key point is that floating-point numbers are approximations, not exact values. The fraction 1/3 cannot be represented exactly in binary, so Python uses an approximation that’s very close but not perfect.
For practical work:
- Use
round()for display purposes - Use
math.isclose()for float comparisons - Use
Decimalwhen precision is critical (like financial calculations)
Python is working correctly—the result is the closest possible representation in IEEE 754 floating-point format.
Final Words + More Resources
My intention with this article was to help others share my knowledge and experience. If you want to contact me, you can contact by email: Email me
Here are also the most important links from this article along with some further resources that will help you in this scope:
- 👨💻 Python Floating-Point Arithmetic Guide
- 👨💻 IEEE 754 Floating-Point Standard
- 👨💻 What Every Computer Scientist Should Know About Floating-Point
- 👨💻 Python math.isclose() Documentation
- 👨💻 Python Decimal Module Documentation
Oh, and if you found these resources useful, don’t forget to support me by starring the repo on GitHub!
Comments