Float to Fraction转换:识别循环小数

时间:2014-03-09 12:56:52

标签: python math fractions

我目前正在实施Fraction class来培训我的OOP技能,而且我遇到了一个问题...在我的课堂上,你可以在math之间进行Fraction次操作:

  • 分数&分数
  • 整数&分数
  • 分数&整数

我想添加两个:

  • 分数&浮
  • Float&分数

因为当我使用整数时,我所做的就是将它们设为float,分母为1,我希望在使用Fraction进行操作时,创建代表该float的{​​{1}}给定Fraction。这就是我遇到问题的地方。

首先,了解我的class class Fraction(object): def __init__(self,num,den=1,reduce=True): # only accept integers or convertable strings if not(type(num) == int and type(den) == int): if type(num) == str: try: num = int(num) except ValueError: raise RuntimeError("You can only pass to the numerator and \ denominator integers or integer convertable strings!") else: raise RuntimeError("You can only pass to the numerator and \ denominator integers or integer convertable strings!") if type(den) == str: try: den = int(den) except ValueError: raise RuntimeError("You can only pass to the numerator and \ denominator integers or integer convertable strings!") else: raise RuntimeError("You can only pass to the numerator and \ denominator integers or integer convertable strings!") # don't accept fractions with denominator 0 if den == 0: raise ZeroDivisionError("The denominator must not be 0") # if both num and den are negative, flip both if num < 0 and den < 0: num = abs(num) den = abs(num) # if only the den is negative, change the "-" to the numerator elif den < 0: num *= -1 den = abs(den) self.num = num self.den = den # the self.auto is a variable that will tell us if we are supposed to #automatically reduce the Fraction to its lower terms. when doing some #maths, if either one of the fractions has self.auto==False, the result #will also have self.auto==False self.auto = reduce if self.auto: self.reduce() def float_to_fraction(f): '''should not be called by an instance of a Fraction, since it does not\ accept, purposedly, the "self" argument. Instead, call it as\ Fraction.float_to_fraction to create a new Fraction with a given float''' # Start by making the number a string f = str(f) exp = "" # If the number has an exponent (is multiplied by 10 to the power of sth #store it for later. if "e" in f: # Get the "e+N" or "e-N" exp = f[f.index("e"):] # Slice the exponent from the string f = f[:f.index("e")] # Start the numerator and the denominator num = "0" den = "1" # Variable to check if we passed a ".", marking the decimal part of a #number decimal = False for char in f: if char != ".": # Add the current char to the numerator num += char if decimal: # If we are to the right of the ".", also add a 0 to the #denominator to keep proportion den += "0" # Slice parsed character f = f[1:] if char == ".": # Tell the function we are now going to the decimal part of the #float. decimal = True # Slice the "." f = f[1:] # Parse the exponent, if there is one if exp != "": # If it is a negative exponent, we should make the denominator bigger if exp[1] == "-": # Add as many 0s to the den as the absolute value of what is to #the right of the "-" sign. e.g.: if exp = "e-12", add 12 zeros den += "0"*int(exp[2:]) # Same stuff as above, but in the numerator if exp[1] == "+": num += "0"*int(exp[2:]) # Last, return the Fraction object with the parsed num and den! return Fraction(int(num),int(den))

所需的最低代码
float_to_fraction()

我的float功能可以100%准确地将给定的Fraction转换为0.123123123123。但是,正如我从数学课中记得的那样,一个带有n位长周期的循环小数,如0.(123) ...或numerator = cycle,可以用denominator = (as many 9s as the length of the cycle)的分数形式写出来123/999 = 0.(123)

3/9 (=1/3) = 0.(3); 142857/999999 (=1/7) = 0.(142857) float_to_fraction()等等......

但是通过这个实现,如果我传递给3333333333333333/10000000000000000一个像1/3这样的参数,它将解析有限的“0.3333333333333333”,返回此分数:Fraction。它是准确的,因为我传递给函数有限数!如何在此函数中实现一种识别循环小数的方法,因此我可以返回带有denominator = 10^n的{​​{1}},而不是带有9的负载的分母。

1 个答案:

答案 0 :(得分:0)

将十进制表达式转换为近似理性的最佳方法是通过连续的分数扩展。

对于x = 0.123123123123,这导致

r=x, 
a[0]=floor(r)=0, r=r-a[0], r=1/r=8.121951219520,
a[1]=floor(r)=8, r=r-a[1], r=1/r=8.199999999453,
a[2]=floor(r)=8, r=r-a[2], r=1/r=5.000000013653,
a[3]=floor(r)=5, r=r-a[3], r=1/r=73243975.48780,

此时r-a[3]<1e-5迭代停止。找到的有理逼近是

x=1/(8+1/(8+1/5))=1/(8+5/41)=41/333 (=123/999)

中间收敛是

1/8=0.125,      x- 1/8   = -0.001876876877,
1/(8+1/8)=8/65, x- 8/65  =  0.0000462000460,
41/333,         x-41/333 = -1.231231231231e-13.