Python多精度理性比较:分数、mpq和mp

2024-09-28 19:31:20 发布

您现在位置:Python中文网/ 问答频道 /正文

我知道浮点计算由于其性质而不精确。我想找出做多精度定量比较的最佳库/方法。我在比较分数,mpq和mpfr。后面两个来自gmpy2库。第一个来自分数包。我用的是Python3.3

这是我用来比较的剧本。写得不太好,很简单。在

from fractions import Fraction
from gmpy2 import mpq, mpfr
import time

# This script compares gmpy2 library and Fraction library

total_pass_mpq = 0
total_pass_mpfr = 0
total_pass_frc = 0

a = mpq("-3.232429")
a_ = Fraction("-3.232429")
a__ = mpfr("-3.232429")
if str(float(a)) == "-3.232429":
    total_pass_mpq +=1
if str(float(a_)) == "-3.232429":
    total_pass_frc += 1
if str(float(a__)) == "-3.232429":
    total_pass_mpfr += 1

b = mpq("604.08")
c = mpq("1.979")
b_ = Fraction("604.08")
c_ = Fraction("1.979")
b__ = mpfr("604.08")
c__ = mpfr("1.979")
if str(float(b*c)) == "1195.47432":
    total_pass_mpq += 1
if str(float(b_*c_)) == "1195.47432":
    total_pass_frc += 1
if str(float(b__*c__)) == "1195.47432":
    total_pass_mpfr += 1

d = mpq(604.08)
e = mpq(1.979)
d_ = Fraction(604.08)
e_ = Fraction(1.979)
d__ = mpfr(604.08)
e__ = mpfr(1.979)
if str(float(d*e)) == "1195.47432":
    total_pass_mpq += 1
if str(float(d_*e_)) == "1195.47432":
    total_pass_frc += 1
if str(float(d__*e__)) == "1195.47432":
    total_pass_mpfr += 1

f = mpq(-3.232429)
f_ = Fraction(-3.232429)
f__ = mpfr(-3.232429)
if str(float(f)) == "-3.232429":
    total_pass_mpq +=1
if str(float(f_)) == "-3.232429":
    total_pass_frc += 1
if str(float(f__)) == "-3.232429":
    total_pass_mpfr +=1

g = mpq(503.79)
g_ = Fraction(503.79)
g__ = mpfr(503.79)
h = mpq(0.07)
h_ = Fraction(0.07)
h__ = mpfr(0.07)
if str(float(g*(1+h))) == "539.0553":
    total_pass_mpq += 1
if str(float(g_*(1+h_))) == "539.0553":
    total_pass_frc += 1
if str(float(g__*(1+h__))) == "539.0553":
    total_pass_mpfr += 1

print("Total passed mpq: " + str(total_pass_mpq))
print("Total passed Fraction: " + str(total_pass_frc))
print("Total passed mpfr: " + str(total_pass_mpfr))

start_mpq = time.time()
for i in range(0, 50000):
    y = mpq(0.32329)
    z = mpq(-1)
    yz = y*z
end_mpq = time.time()
print("Time for executing mpq: " + str(end_mpq - start_mpq))

start_frc = time.time()
for j in range(0, 50000):
    y = Fraction(0.32329)
    z = Fraction(-1)
    yz_ = y*z
end_frc = time.time()
print("Time for executing frc: " + str(end_frc - start_frc))

start_frc_2 = time.time()
for j_ in range(0, 50000):
    y = Fraction(0.32329)
    z = Fraction(-1)
    yz_2 = y*z
end_frc_2 = time.time()
print("Time for executing frc str: " + str(end_frc_2 - start_frc_2))

start_mpfr = time.time()
for k in range(0, 50000):
    y = mpfr(0.32329)
    z = mpfr(-1)
    yz__ = y*z
end_mpfr = time.time()
print("Time for executing mpfr: " + str(end_mpfr - start_mpfr))

start_mpfr_2 = time.time()
for k_ in range(0, 50000):
    y = mpfr("0.32329")
    z = mpfr("-1")
    yz__2 = y*z
end_mpfr_2 = time.time()
print("Time for executing mpfr str: " + str(end_mpfr_2 - start_mpfr_2))

结果是:

^{pr2}$

所以基本上我得到的结果是分数是最精确的,但是它非常慢。对于这个问题,我想问

  1. 你觉得我还应该试试别的案子吗?在
  2. 还有别的图书馆吗?在
  3. 如果速度很重要,有没有办法使用gmpy2库来提高精度?在

Tags: inforiftimepassfloatstartfrc
1条回答
网友
1楼 · 发布于 2024-09-28 19:31:20

float(mpq)调用GMP库函数mpq_get_q。我检查了GMP源代码,mpq_get_d将中间结果舍入到0。它无法计算正确的四舍五入结果。(在本例中,正确的四舍五入意味着四舍五入到最近,并且与偶数的关系)因此它有时会与float(Fraction)不同。在

GMP库没有针对浮点计算进行优化。要获得正确的四舍五入浮点值,应该使用MFPR库(也称为mpfr中的mpfr类型)。在

mpq转换为float的最准确方法是先将其转换为mpfr。为了避免双重取整,您应该将mpq转换为mpfr,精确到53位。所以float(mpfr(mpq, 53))。(默认精度目前为53位,但将来可能会改变。建议指定所需的精度,或确保默认上下文的精度设置为53。)此更改使mpq和{}在示例中返回相同的结果。在

还有一个结果是不同的。这正是中间mpfr计算四舍五入到当前精度(本例中为53位)这一事实中固有的。在

更新以回答@mattsun的问题。

为什么mpfr("503.79")*(mpfr("1")+mpfr("0.07"))不等于“539.0553”?在

Python的float类型和gmpy2的mpfr类型都使用二进制或基数2表示。当我们处理数字时,我们通常使用十进制或基数-10表示。就像1/3cannon用十进制算法精确表示一样,大多数十进制数不能用二进制表示法精确表示。计算的值与给定值相近,但不完全相等。错误会累积起来,结果只会与您的预期值稍有不同。在

有两种选择:

1)将字符串格式化为所需的十进制格式。在

2)使用decimal库。在

免责声明:我维护gmpy2。在

相关问题 更多 >