我知道浮點計算由於其性質而不準確。我試圖找出最好的庫/方式來進行多精度定量比較。我在比較分數,mpq和mpfr。後兩者來自gmpy2庫。第一個來自分數包。我正在使用python3.3Python多精度合理比較:分數,mpq和mpfr
這是我用來比較的腳本。寫得不好,很簡單。
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))
這是結果:
Total passed mpq: 3
Total passed Fraction: 5
Total passed mpfr: 4
Time for executing mpq: 0.04700875282287598
Time for executing frc: 2.1327619552612305
Time for executing frc str: 2.0934295654296875
Time for executing mpfr: 0.05441713333129883
Time for executing mpfr str: 0.12844634056091309
所以基本上我已經得到了結果分數是最準確之一,但它是超慢。對於這個問題,我想問,
- 有沒有其他情況下,你認爲我也應該嘗試?
- 任何其他庫?
- 如果速度很重要,有沒有辦法提高使用gmpy2庫的精度?
'mpq'和'Fraction'應該是相等的(實際上是無限的)精度,因爲它們都存儲任意的精度'int's作爲分子和分母。如果他們聲稱他們兩個沒有匹配的精度,我懷疑你的測試設計得不好(依靠浮點表示太多)。 'mpq'應該基本上是'Fraction'的更快版本,就是這樣。不過,在這兩種情況下,從「浮動」初始化都是要求麻煩的; '浮動'有代表性的問題,不同的有理數字類型可能會有不同的轉換。 – ShadowRanger
@ShadowRanger例如,'float(mpq(「 - 3.232429」))''給我'-3.2324289999999998'而'float(Fraction(「 - 3.232429」))'給我'-3.232429'。你認爲這是預期的嗎? – mattsun
你假設圖書館的目標是處理浮點數學。不是。只要你離開理性數字領域,圖書館就不在他們預期的用例範圍內。我不清楚「錯誤」究竟在哪裏蔓延,但從「mpq」返回到「float」的轉換可能會因爲GMP中的精度太高而不同(其中浮點錯誤隨精度而變化;可能有助於轉換自己'mympq.numerator/mympq.denominator'讓Python做到這一點),而不是太少。如果你正在從「float」轉換,並且你沒有正確地進行有理數的數學運算。 – ShadowRanger