在 Python 2.7 中四舍五入时分数不太准确
Less accurate fractions when rounding in Python 2.7
大家好,我是 python 的新手,这是我的第一个项目。我正在创建一个计算器,当我输入圆的周长时,它会为我计算直径。例如摩托车上的把手,无需取下把手。
我让它工作了,但我真的需要它不太准确,比如四舍五入到最近的 1/8。如果我输入 2.75,它会完美运行,但如果我输入 2.76,它会给出疯狂的分数。我仍然希望它读到 7/8,直到它超过 1.0
的一半
这是我目前的所有信息,如果您能提供任何帮助,我们将不胜感激。
from fractions import Fraction
print "Do you wish to calculate the Diameter or Radius from a perimeter measurement? Type 'd' or 'r'"
var = raw_input("Please type 'd' or 'r'")
if var == 'd':
print "Now type the perimeter measurement for the diameter you would like calculate."
cir = float(raw_input())
answer = cir/3.1415926535
rnd = round(answer, 3 )
frac = Fraction(rnd).limit_denominator()
print rnd
print "The diameter of a %s perimeter is" % cir, frac
elif var == 'r':
print "Now type the perimeter measurement for the Radius you would like to calculate."
cir = float(raw_input())
answer = cir/3.1415926535/2
print "The Radius of a %s perimeter is" % cir, answer
else:
print "Error: You did not type 'd' or 'r' Please run again"
您可以四舍五入到最接近的 1/8。
In [1]: from fractions import Fraction
In [14]: Fraction(round(2.6*8)/8).limit_denominator()
Out[14]: Fraction(21, 8)
In [4]: Fraction(round(2.75*8)/8).limit_denominator()
Out[4]: Fraction(11, 4)
In [5]: Fraction(round(2.9*8)/8).limit_denominator()
Out[5]: Fraction(23, 8)
要同分母就简单了
denominator = 8
rnd = round(answer * denominator)
frac = Fraction(int(rnd), denonimator)
之前的所有方法都使用了错误的round(x*8)/8
方法;当然,当我着急的时候,我有时(不经常)使用它,但这是一种错误的方法。
方法一(最正统)
根据连分数理论,有四个最佳近似到2.76,即:
2, 3, 11/4, 69/25
您可能会争辩说 11/4 与 22/8(如所问)相同,但您不能指望它对任何数字都适用。以 Pi 为例; round(3.1415926*8)/8
是 25/8,与 22/7 相比,这是一个非常差的近似值:22/7 实际上将 Pi 近似为 1/8,但甚至更好(虽然比 25/8 更简单) ! 楼主想要的是1/8的近似值。看看以下三个分数:22/7、25/8、314/100;都将 Pi 近似为 1/8,但您会选择哪一个(可能是第一个;现在:第一个不仅是三个分数中最简单的;它也是最准确的)?比 22/7 更好的最简单分数跳到小于 1e-4 的精度(即 333/106)!
此外,如果你想接近0.5,你不能满足于4/8!当然 fractions
模块可能会在初始化时取消它,但这无论如何都是一个非常糟糕的迹象:你的方法不想产生像 4/8 这样的东西,即使是作为中间步骤也是如此!
开个玩笑:拿0.33333333...试试round(x*8)/8
方法;你会发现 3/8 近似于 0.33333333... 到 1/8,这当然是正确的,但是... 怎么礼貌地说呢?
看看下面的函数;你可以放心地依靠它来近似一个数字:
from fractions import Fraction
def rationalize(x, maxden=1000):
p0, p1 = 0, 1
q0, q1 = 1, 0
a = int(x) if x >= 0 else int(x-1)
while q1 <= maxden:
p = a*p1 + p0
q = a*q1 + q0
p0, p1 = p1, p
q0, q1 = q1, q
if x==a:
if q1 <= maxden: return Fraction(p1, q1)
else: return Fraction(p0, q0)
x = 1/(x-a)
a = int(x)
return Fraction(p0, q0)
如果你用 maxden=8
与 Pi 一起尝试,你会得到预期的 22/7(不再是疯狂的 25/8)。
函数returns 收敛 到您的数字,该数字是从数字的连分式扩展中的连续部分商构建的。请参阅 https://en.wikipedia.org/wiki/Diophantine_approximation
中的说明
方法二
一些计算机代数系统也使用线性整数关系算法(例如PSLQ)来解决这个问题;例如 Sympy 使用 mpmath.pslq
方法来完成它。这非常方便并且给出了很好的结果,因为 PSLQ returns 向量给出了 1 和 x 之间具有最小范数的整数关系。但还是比另一种方法复杂。
大家好,我是 python 的新手,这是我的第一个项目。我正在创建一个计算器,当我输入圆的周长时,它会为我计算直径。例如摩托车上的把手,无需取下把手。
我让它工作了,但我真的需要它不太准确,比如四舍五入到最近的 1/8。如果我输入 2.75,它会完美运行,但如果我输入 2.76,它会给出疯狂的分数。我仍然希望它读到 7/8,直到它超过 1.0
的一半这是我目前的所有信息,如果您能提供任何帮助,我们将不胜感激。
from fractions import Fraction
print "Do you wish to calculate the Diameter or Radius from a perimeter measurement? Type 'd' or 'r'"
var = raw_input("Please type 'd' or 'r'")
if var == 'd':
print "Now type the perimeter measurement for the diameter you would like calculate."
cir = float(raw_input())
answer = cir/3.1415926535
rnd = round(answer, 3 )
frac = Fraction(rnd).limit_denominator()
print rnd
print "The diameter of a %s perimeter is" % cir, frac
elif var == 'r':
print "Now type the perimeter measurement for the Radius you would like to calculate."
cir = float(raw_input())
answer = cir/3.1415926535/2
print "The Radius of a %s perimeter is" % cir, answer
else:
print "Error: You did not type 'd' or 'r' Please run again"
您可以四舍五入到最接近的 1/8。
In [1]: from fractions import Fraction
In [14]: Fraction(round(2.6*8)/8).limit_denominator()
Out[14]: Fraction(21, 8)
In [4]: Fraction(round(2.75*8)/8).limit_denominator()
Out[4]: Fraction(11, 4)
In [5]: Fraction(round(2.9*8)/8).limit_denominator()
Out[5]: Fraction(23, 8)
要同分母就简单了
denominator = 8
rnd = round(answer * denominator)
frac = Fraction(int(rnd), denonimator)
之前的所有方法都使用了错误的round(x*8)/8
方法;当然,当我着急的时候,我有时(不经常)使用它,但这是一种错误的方法。
方法一(最正统)
根据连分数理论,有四个最佳近似到2.76,即:
2, 3, 11/4, 69/25
您可能会争辩说 11/4 与 22/8(如所问)相同,但您不能指望它对任何数字都适用。以 Pi 为例; round(3.1415926*8)/8
是 25/8,与 22/7 相比,这是一个非常差的近似值:22/7 实际上将 Pi 近似为 1/8,但甚至更好(虽然比 25/8 更简单) ! 楼主想要的是1/8的近似值。看看以下三个分数:22/7、25/8、314/100;都将 Pi 近似为 1/8,但您会选择哪一个(可能是第一个;现在:第一个不仅是三个分数中最简单的;它也是最准确的)?比 22/7 更好的最简单分数跳到小于 1e-4 的精度(即 333/106)!
此外,如果你想接近0.5,你不能满足于4/8!当然 fractions
模块可能会在初始化时取消它,但这无论如何都是一个非常糟糕的迹象:你的方法不想产生像 4/8 这样的东西,即使是作为中间步骤也是如此!
开个玩笑:拿0.33333333...试试round(x*8)/8
方法;你会发现 3/8 近似于 0.33333333... 到 1/8,这当然是正确的,但是... 怎么礼貌地说呢?
看看下面的函数;你可以放心地依靠它来近似一个数字:
from fractions import Fraction
def rationalize(x, maxden=1000):
p0, p1 = 0, 1
q0, q1 = 1, 0
a = int(x) if x >= 0 else int(x-1)
while q1 <= maxden:
p = a*p1 + p0
q = a*q1 + q0
p0, p1 = p1, p
q0, q1 = q1, q
if x==a:
if q1 <= maxden: return Fraction(p1, q1)
else: return Fraction(p0, q0)
x = 1/(x-a)
a = int(x)
return Fraction(p0, q0)
如果你用 maxden=8
与 Pi 一起尝试,你会得到预期的 22/7(不再是疯狂的 25/8)。
函数returns 收敛 到您的数字,该数字是从数字的连分式扩展中的连续部分商构建的。请参阅 https://en.wikipedia.org/wiki/Diophantine_approximation
中的说明方法二
一些计算机代数系统也使用线性整数关系算法(例如PSLQ)来解决这个问题;例如 Sympy 使用 mpmath.pslq
方法来完成它。这非常方便并且给出了很好的结果,因为 PSLQ returns 向量给出了 1 和 x 之间具有最小范数的整数关系。但还是比另一种方法复杂。