开放的编程资料库

当前位置:我爱分享网 > Python教程 > 正文

Python 十进制

PythonDecimal教程展示了如何在Python中使用Decimal执行高精度计算。

Python小数

Pythondecimal模块支持快速正确舍入的decimal浮点运算。

默认情况下,Python将任何包含小数点的数字解释为双精度浮点数。Decimal是一种浮点数类型,比浮点数精度更高,范围更小。它适用于财务和货币计算。它也更接近于人类处理数字的方式。

与基于硬件的二进制浮点数不同,decimal模块具有用户可更改的精度,对于给定问题,该精度可以根据需要设置。默认精度为28位。

某些值无法用浮点数据类型准确表示。例如,将0.1值存储在float(二进制浮点值)变量中,我们只能得到该值的近似值。同样,1/3的值也不能用十进制浮点型精确表示。

这两种类型都不是完美的;一般来说,decimal类型更适用于金融和货币计算,而double/float类型更适用于科学计算。

Python十进制默认精度

Decimal的默认精度为28位,而float有18位。

#!/usr/bin/python

from decimal import Decimal

x = 1 / 3
print(type(x))
print(x)

print("-----------------------")

y = Decimal(1) / Decimal(3)
print(type(y))
print(y)

该示例比较了Python中两种浮点类型的精度。

$ ./defprec.py
<class 'float'>
0.3333333333333333
-----------------------
<class 'decimal.Decimal'>
0.3333333333333333333333333333

Python比较浮点值

比较浮点值时应谨慎行事。虽然在许多现实世界的问题中,一个小错误可以忽略不计,但金融和货币计算必须准确。

#!/usr/bin/python

from decimal import Decimal

x = 0.1 + 0.1 + 0.1

print(x == 0.3)
print(x)

print("----------------------")

x = Decimal('0.1') + Decimal('0.1') + Decimal('0.1')

print(x == Decimal('0.3'))
print(float(x) == 0.3)
print(x)

该示例执行浮点值与内置floatDecimal类型的比较。

$ ./comparing.py
False
0.30000000000000004
----------------------
True
True
0.3

由于float类型中的一个小错误,0.1+0.1+0.1==0.3产生False。使用Decimal类型,我们得到了预期的输出。

PythonDecimal改变精度

可以更改Decimal类型的默认精度。在下面的示例中,我们还使用了mpmath模块,它是一个用于任意精度浮点的库-点算术。

$ pip install mpmath

我们需要先安装mpmath

#!/usr/bin/python

from decimal import Decimal, getcontext
import math

import mpmath

getcontext().prec = 50
mpmath.mp.dps = 50
num = Decimal(1) / Decimal(7)

num2 = mpmath.mpf(1) / mpmath.mpf(7)

print("   math.sqrt: {0}".format(Decimal(math.sqrt(num))))
print("decimal.sqrt: {0}".format(num.sqrt()))
print(" mpmath.sqrt: {0}".format(mpmath.sqrt(num2)))
print('actual value: 0.3779644730092272272145165362341800608157513118689214')

在示例中,我们将精度更改为50位。我们比较了math.sqrtDecimal的sqrtmpmath.sqrt函数的准确性。

$ alter_precision.py
    math.sqrt: 0.37796447300922719758631274089566431939601898193359375
 decimal.sqrt: 0.37796447300922722721451653623418006081575131186892
  mpmath.sqrt: 0.37796447300922722721451653623418006081575131186892
 actual value: 0.3779644730092272272145165362341800608157513118689214

Python十进制舍入

Decimal类型提供了几个舍入选项:

  • ROUND_CEILING-总是向上舍入到无穷大
  • ROUND_DOWN-总是向零舍入
  • ROUND_FLOOR-总是向下舍入到负无穷大
  • ROUND_HALF_DOWN-如果最后一个有效数字大于或等于5,则从零舍入,否则向零舍入
  • ROUND_HALF_EVEN-与ROUND_HALF_DOWN类似,只是如果值为5,则检查前面的数字;偶数会使结果向下舍入,奇数会使结果向上舍入。
  • ROUND_HALF_UP-类似于ROUND_HALF_DOWN,除非最后一位有效数字为5,否则值将从零开始舍入
  • ROUND_UP-从零舍入
  • ROUND_05UP-如果最后一位数字是0或5,则从零舍入,否则朝零舍入
#!/usr/bin/python

import decimal

context = decimal.getcontext()

rounding_modes = [
    'ROUND_CEILING',
    'ROUND_DOWN',
    'ROUND_FLOOR',
    'ROUND_HALF_DOWN',
    'ROUND_HALF_EVEN',
    'ROUND_HALF_UP',
    'ROUND_UP',
    'ROUND_05UP',
    ]

col_lines = '-' * 10

print(f"{' ':20} {'1/7 (1)':^10} {'1/7 (2)':^10} {'1/7 (3)':^10} {'1/7 (4)':^10}")
print(f"{' ':20} {col_lines:^10} {col_lines:^10} {col_lines:^10} {col_lines:^10}")

for mode in rounding_modes:

    print(f'{mode:20}', end=' ')

    for precision in [1, 2, 3, 4]:

        context.prec = precision
        context.rounding = getattr(decimal, mode)
        value = decimal.Decimal(1) / decimal.Decimal(7)
        print(f'{value:<10}', end=' ')
    print()

print('********************************************************************')

print(f"{' ':20} {'-1/7 (1)':^10} {'-1/7 (2)':^10} {'-1/7 (3)':^10} {'-1/7 (4)':^10}")
print(f"{' ':20} {col_lines:^10} {col_lines:^10} {col_lines:^10} {col_lines:^10}")


for mode in rounding_modes:

    print(f'{mode:20}', end=' ')

    for precision in [1, 2, 3, 4]:

        context.prec = precision
        context.rounding = getattr(decimal, mode)
        value = decimal.Decimal(-1) / decimal.Decimal(7)
        print(f'{value:<10}', end=' ')

    print()

该示例显示了1/7-1/7表达式的可用舍入选项。

$ ./rounding.py
                     1/7 (1)    1/7 (2)    1/7 (3)    1/7 (4)
                     ---------- ---------- ---------- ----------
ROUND_CEILING        0.2        0.15       0.143      0.1429
ROUND_DOWN           0.1        0.14       0.142      0.1428
ROUND_FLOOR          0.1        0.14       0.142      0.1428
ROUND_HALF_DOWN      0.1        0.14       0.143      0.1429
ROUND_HALF_EVEN      0.1        0.14       0.143      0.1429
ROUND_HALF_UP        0.1        0.14       0.143      0.1429
ROUND_UP             0.2        0.15       0.143      0.1429
ROUND_05UP           0.1        0.14       0.142      0.1428
********************************************************************
                     -1/7 (1)   -1/7 (2)   -1/7 (3)   -1/7 (4)
                     ---------- ---------- ---------- ----------
ROUND_CEILING        -0.1       -0.14      -0.142     -0.1428
ROUND_DOWN           -0.1       -0.14      -0.142     -0.1428
ROUND_FLOOR          -0.2       -0.15      -0.143     -0.1429
ROUND_HALF_DOWN      -0.1       -0.14      -0.143     -0.1429
ROUND_HALF_EVEN      -0.1       -0.14      -0.143     -0.1429
ROUND_HALF_UP        -0.1       -0.14      -0.143     -0.1429
ROUND_UP             -0.2       -0.15      -0.143     -0.1429
ROUND_05UP           -0.1       -0.14      -0.142     -0.1428

Python分数

我们可以使用Fraction处理有理数。

#!/usr/bin/python

from decimal import Decimal
from fractions import Fraction

x = Decimal(1) / Decimal(3)
y = x * Decimal(3)

print(y == Decimal(1))
print(x)
print(y)

print("-----------------------")

u = Fraction(1) / Fraction(3)
v = u * Fraction(3)

print(v == 1)
print(u)
print(v)

Decimal不能精确表示1/3表达式。在某些情况下,我们可以使用Fraction类型来获得准确的结果。

$ ./fract.py
False
0.3333333333333333333333333333
0.9999999999999999999999999999
-----------------------
True
1/3
1

PythonSymPy理性

也可以使用SymPy的Rational类型来处理有理数。

$ pip install sympy

我们安装了sympy模块。

#!/usr/bin/python

from sympy import Rational

r1 = Rational(1/10)
r2 = Rational(1/10)
r3 = Rational(1/10)

val = (r1 + r2 + r3) * 3
print(val.evalf())

val2 = (1/10 + 1/10 + 1/10) * 3
print(val2)

在示例中,我们比较了Rational和内置float的精度(1/10+1/10+1/10)*3表达式。

$ ./symbolic.py
0.900000000000000
0.9000000000000001

float类型有一个小错误。

在本教程中,我们使用了PythonDecimal类型。

列出所有Python教程。

未经允许不得转载:我爱分享网 » Python 十进制

感觉很棒!可以赞赏支持我哟~

赞(0) 打赏