如何用Python进行精确的小数计算
在这篇文章中,我们将学习如何在Python中进行精确的小数计算。
使用的方法
- 使用十进制模块的Decimal()函数
-
使用数学模块的fsum()函数
浮点数 不能准确地表示所有的10进制数,这是一个众所周知的缺点。此外,即使是直接的数学计算也很少有错误。例如 –
例子
x = 4.2
y = 3.1
# printing the sum of both the variables
print("x + y =", x + y)
# checking if the sum is both the variables is equal to 7.3
print((x + y) == 7.3)
输出
在执行过程中,上述程序将产生以下输出
x + y = 7.300000000000001
False
这些错误是CPU的一个 “特征”,它是系统的基础,也是其浮点单元所使用的IEEE 754算术标准。如果你使用浮点实例编写代码,你没有办法防止这种错误,因为Python的浮点数据类型使用本地表示法保存数据。
使用 十进制模块 会给你带来更大的准确性,但要付出一些性能的代价。让我们看看下面的情况。
方法1:使用十进制模块的Decimal()函数
例子
# importing Decimal from decimal module
from decimal import Decimal
x = Decimal('4.2')
y = Decimal('3.1')
# printing the sum of both the variables
print("x + y =", x + y)
# checking if the sum is both the variables is equal to 7.3 using by passing the sum to the Decimal Function
print((x + y) == Decimal('7.3'))
输出
在执行过程中,上述程序将产生以下输出
x + y = 7.3
True
在上面的代码中,一开始会显得有点奇怪,即把数字指定为 字符串。 然而,小数点对象完全按照你希望的那样工作(支持所有常见的数学运算,等等)。当你打印它们或在字符串格式化功能中利用它们时,它们看起来就像普通的数字。
能够控制计算的几个方面,如数字的数量和四舍五入,是 小数 的一个关键特征 。
例子
要执行这个操作,请创建一个本地上下文并修改其设置。
# importing localcontext from decimal module
from decimal import localcontext
x = Decimal('2.3')
y = Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
# rounding the number upto 3 digits i.e, precision 3
context.prec = 3
# Dividing x by y with precision set to 3
print(x / y)
输出
在执行过程中,上述程序将产生以下输出
0.8518518518518518518518518519
0.852
将精度值增加到’60’,以提高精度
例子
# importing localcontext from decimal module
import decimal
from decimal import localcontext
x = decimal.Decimal('2.3')
y = decimal.Decimal('2.7')
# dividing x by y(returns as a floating-point number)
print(x / y)
with localcontext() as context:
# Rounding the number upto 60 digits i.e, precision 60
context.prec = 60
# Dividing x by y with precision set to 3
print(x / y)
输出
在执行过程中,上述程序将产生以下输出
0.8518518518518518518518518519
0.851851851851851851851851851851851851851851851851851851851852
方法2:使用数学模块的fsum()函数
十进制模块实现了IBM的 “通用十进制算术规范”。
不言而喻,有大量的定制选择,超出了本文的范围。
Python 初学者可能会想利用十进制模块来解决浮点数据类型所报告的精度问题。了解你的应用程序领域也很重要。在处理科学或工程问题、计算机图形或其他大多数科学性质的东西时,利用普通的浮点类型更为典型。
例如,实际世界中很少有元素的测量精度能达到 浮点数的17位。 因此,即使是微小的计算错误也没有影响。 本地浮点运算 的速度也明显 更快, 如果你需要运行大量的计算,这一点至关重要。
例子
然而,你不可能完全避免错误。数学家已经对众多算法进行了广泛的研究,有些算法在处理错误方面比其他算法更好。此外,像减法取消和大小数相加的做法所产生的后果,也需要注意一些。
inputList = [1.23e+18, 1, -1.23e+18]
# observe how the 1 disappears here if we perform sum() on the list
print(sum(inputList))
输出
在执行时,上述程序将产生以下输出:
0.0
fsum()找到一个给定的范围或一个可迭代对象之间的和。它需要导入数学库。它在数学计算中被广泛使用。
语法
下面是该函数的语法。
maths.fsum( iterable )
迭代器可以是一个范围、数组或列表。
返回类型 –
它返回一个浮点数。
例子
下面的例子可以用来解决 math.fsum() 中更精确的实现 --
# importing math module
import math
# input list
inputList = [1.23e+18, 1, -1.23e+18]
# adding the sum of elements of the list using the fsum() function
print(math.fsum(inputList))
输出
在执行过程中,上述程序将产生以下输出
1.0
相比之下,你实际上需要研究和了解其他算法的错误传播特性。
尽管这样,处理金融等主题的程序是最经常使用小数模块的地方。当这种系统的计算出现微小的不准确时,会令人感到非常不愉快。
因此,十进制模块提供了一种避免这种情况的手段。当Python与数据库接口时,十进制对象又经常被遇到,特别是在访问财务数据时。
总结
我们在这篇文章中了解了正常计算在特殊情况下是如何失败的,以及为什么我们需要正确的小数计算。我们学习了如何用两个独立的函数进行准确的小数计算:decimal()和fsum()。我们还学习了如何使用localcontext()函数来设置结果的精度。