gpt4 book ai didi

python - CPython 和 PyPy 十进制运算性能

转载 作者:行者123 更新时间:2023-12-04 03:31:46 26 4
gpt4 key购买 nike

我想用数百万个数据点运行一些 100k+ 模拟,这些数据点表示为小数。我选择小数而不是浮点数来获得浮点精度和易于单元测试我的逻辑(因为 0.1 + 0.1 + 0.1 与浮点数不等于 0.3...)。
我希望通过使用 PyPy 来加速模拟。但是在我的测试过程中,我遇到 PyPy 不处理 decimal.Decimal甚至 _pydecimal.Decimal完全好 - 并且比 CPython 解释器慢得多(它使用 C 进行 decimal.Decimal 算术)。所以我复制/粘贴了我的整个代码库并替换了所有 Decimal s 与 float s 并且性能提升是巨大的:PyPy 比 CPython 快 x60-x70 倍 - 牺牲准确性。
是否有任何解决方案可以在 PyPy 中使用 Decimals 精度来提高性能?我“可以”维护两个代码库:float批量运行 10 万次模拟,Decimal用于稍后检查有趣的结果 - 但这需要维护两个代码库的开销......
以下是我在 Raspberry Pi 4 (Ubuntu Server 20.10, 4 x 1.5GHZ ARM Cortex-A72, 8GB RAM) 上运行的一些简单测试用于繁殖:
test_decimal.py

import time
from decimal import Decimal

start = time.time()
val = Decimal('1.0')
mul = Decimal('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"decimal.Decimal: {val:.8f} in {round(end-start,4)} sec")
test_pydecimal.py
import time
from _pydecimal import Decimal

start = time.time()
val = Decimal('1.0')
mul = Decimal('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"pydecimal.Decimal: {val:.8f} in {round(end-start,4)} sec")
test_float.py
import time
from decimal import Decimal

start = time.time()
val = float('1.0')
mul = float('1.000001')
for i in range(10 * 1000 * 1000):
val *= mul
end = time.time()
print(f"float: {val:.8f} in {round(end-start,4)} sec")
结果


测试
Python 3.8.6 (GCC 10.2.0)
Python 3.6.9 -PyPy 7.3.1 与 GCC 10.2.0


test_decimal
5.1131 秒
55.0829 秒

test_pydecimal
315.4012 秒
40.1771 秒

测试 float
2.5607 秒
0.1273 秒


编辑 #1:
  • 更新了示例(使用预先计算的乘法器,测量 print 之外的时间)和结果表:PyPy 和 CPython 在 Decimals 上的性能之间的总体比较保持不变。
  • 模拟主要包括对具有变化值的时间序列数据的基本数学运算(加、减、乘、除)。
  • 最佳答案

    您可以使用 双 double 比任意精度算术(即 Decimal )更快地实现您想要的目标,并且比 double (即 float )更准确。双 double 通常比四精度精度稍低,但大多数平台通常不支持后者。
    doubledouble Python 包实现了这一点并且与 PyPy 兼容。它不支持字符串解析和格式化,但您可以使用以下两种慢速方法来实现:

    from decimal import Decimal
    from doubledouble import DoubleDouble

    def ddFromStr(s):
    hi = float(s)
    lo = float(Decimal(s) - Decimal(hi))
    return DoubleDouble(hi, lo)

    def ddToStr(dd):
    return str(Decimal(dd.x) + Decimal(dd.y))
    以下是如何使用它:
    start = time.time()
    val = ddFromStr('1.0')
    mul = ddFromStr('1.000001')
    for i in range(10 * 1000 * 1000):
    val *= mul
    end = time.time()
    print(f"doubledouble.DoubleDouble: {ddToStr(val)} in {round(end-start,4)} sec")
    这是我机器上的结果:
    CPython:
    float: 22026.35564471 in 0.6692 sec
    decimal.Decimal: 22026.35566283 in 1.4355 sec
    doubledouble.DoubleDouble: 22026.35566283 in 11.62 sec

    PyPy:
    float: 22026.35564471 in 0.011 sec
    decimal.Decimal: 22026.35566283 in 16.3268 sec
    doubledouble.DoubleDouble: 22026.355662823 in 0.1184 sec
    如您所见, doubledouble PyPy 上的包明显更快 Decimal在 CPython 上打包,而在这种情况下,两者提供同样准确(截断)的结果。

    关于python - CPython 和 PyPy 十进制运算性能,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/66646850/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com