杰瑞科技汇

Python float与decimal如何选择?

Of course! This is a fundamental and often tricky concept in Python. Let's break down everything you need to know about Python's float type and decimal representation.

Python float与decimal如何选择?-图1
(图片来源网络,侵删)

The Core Problem: Binary Floating-Point

The most important thing to understand is that Python's float type is implemented using a standard called IEEE 754, which uses binary (base-2) to represent numbers.

This causes problems because many common decimal (base-10) fractions, like 1 or 2, cannot be represented perfectly in binary. They are repeating fractions in binary, much like 1/3 is a repeating fraction (333...) in decimal.

The Demonstration

Let's see this in action. You might expect this to be False:

>>> 0.1 + 0.2 == 0.3
False

Why? Because the computer isn't actually storing 1 and 2. It's storing the closest possible binary approximation.

Python float与decimal如何选择?-图2
(图片来源网络,侵删)
>>> format(0.1, '.60f')
'0.1000000000000000055511151231257827021181583404541015625'
>>> format(0.2, '.60f')
'0.200000000000000011102230246251565404236316680908203125'
>>> format(0.3, '.60f')
'0.299999999999999988897769753748434595763683319091796875'
>>> 0.1 + 0.2
0.30000000000000004

The sum of the approximations for 1 and 2 is slightly more than the approximation for 3, leading to the unexpected result.


How to Deal with Floats Correctly

Since this is an inherent limitation of how computers store numbers, not a bug in Python, we need strategies to handle it.

For Display and Formatting (The Easy Fix)

If you just need to display a float in a user-friendly way, use formatting options. They automatically round the number for presentation.

# Using an f-string (Python 3.6+)
>>> price = 99.95
>>> print(f"The price is ${price:.2f}")
The price is $99.95
# Using the format() function
>>> print("The price is ${:.2f}".format(price))
The price is $99.95
# Using the round() function (be careful, see section 3)
>>> round(0.1 + 0.2, 2)
0.3

Key Takeaway: The underlying float value is still imprecise, but the formatted output is what you expect.

Python float与decimal如何选择?-图3
(图片来源网络,侵删)

For High-Precision Arithmetic (The Best Solution)

If you are doing financial calculations, scientific computations, or any situation where precision is critical, you should not use float. Instead, use Python's built-in decimal module.

The decimal module performs decimal (base-10) arithmetic, which avoids the binary floating-point issues entirely.

import decimal
# Create Decimal objects from strings
d1 = decimal.Decimal('0.1')
d2 = decimal.Decimal('0.2')
d3 = decimal.Decimal('0.3')
# Now, the arithmetic is exact
>>> print(d1 + d2)
0.3
>>> d1 + d2 == d3
True

Why use strings? If you create a Decimal from a float, you're just copying the inaccuracy from the float into the Decimal.

# DON'T DO THIS:
bad_decimal = decimal.Decimal(0.1)
print(bad_decimal)  # Still shows the imprecise value

Best Practice: Always initialize Decimal objects from strings or integers.

For Comparison (The "Good Enough" Fix)

For general-purpose programming where you don't need perfect precision but want to avoid the 1 + 0.2 != 0.3 problem, never compare floats for exact equality (). Instead, check if they are "close enough."

You can do this manually:

# Check if the absolute difference is very small
a = 0.1 + 0.2
b = 0.3
if abs(a - b) < 1e-9:  # 1e-9 is 0.000000001
    print("a and b are close enough")

Or, even better, use the math.isclose() function, which is designed for this.

import math
a = 0.1 + 0.2
b = 0.3
>>> math.isclose(a, b)
True
# It also handles relative differences for very large or small numbers
>>> math.isclose(1e9, 1e9 + 1, rel_tol=1e-9)
True

Summary Table: float vs. decimal

Feature float (Floating-Point) decimal.Decimal (Fixed-Point)
Representation Binary (base-2) Decimal (base-10)
Purpose General-purpose scientific and engineering calculations. Financial, monetary, and other applications requiring exact precision.
Performance Very Fast. Implemented in hardware. Slower. Implemented in software.
Precision Limited by system architecture (typically ~15-17 significant decimal digits). Precision is configurable and arbitrary (limited by available memory).
When to Use - Graphics, physics simulations, machine learning.
- When performance is critical and minor precision errors are acceptable.
- Currency calculations ($10.50).
- When you need to guarantee that 1 + 0.2 == 0.3.
Example my_price = 99.95 from decimal import Decimal; my_price = Decimal('99.95')

Final Recommendation

  1. For general-purpose code: Use float but be aware of its limitations. Never compare floats for exact equality. Use math.isclose() or check if they are within a small tolerance.
  2. For financial or high-precision code: Use the decimal module. It's the right tool for the job and will save you from subtle and hard-to-find bugs.
  3. For display: Always use formatting (like f"{value:.2f}") to present floats to users in a clean, rounded way.
分享:
扫描分享到社交APP
上一篇
下一篇