我认为错误在于您应该只检查以前看到的小数位数是否是循环长度的数字,并且它是在这个长度之前看到的。
我认为最好的方法是使用一些好的数学。
让我们尝试设计一种方法来查找分数的小数表示以及如何知道何时会有重复小数。
了解分数是否会终止(或重复)的最佳方法是查看分母的因式分解(难题)。
求因式分解的方法有很多,但我们真正想知道的是,这个数是否有除 2 或 5 以外的质因数。为什么?那么十进制扩展只是一些数字a / 10 * b。也许 1/2 = .5 = 5/10。 1/20 = .05 = 5/100。等等
所以 10 的因数是 2 和 5,所以我们想知道它是否还有除 2 和 5 以外的其他因数。完美,很简单,只要继续除以 2,直到它不再能被 2 整除,比对 5 做同样的事情。或者反过来。
在我们开始做一些严肃的工作之前,首先我们可能想知道它是否可以被 2 或 5 整除。
def div_by_a_or_b( a, b, number):
return not ( number % a ) or not ( number % b )
然后我们将所有的五除以所有的二并检查数字是否为1
def powers_of_only_2_or_5(number):
numbers_to_check = [ 2, 5 ]
for n in numbers_to_check:
while not number % n: # while it is still divisible by n
number = number // n # divide it by n
return number == 1 # if it is 1 then it was only divisble by the numbers in numbers_to_check
我把它变得更加多态,所以如果你想改变基础,你可以改变它。 (您所需要的只是该基数的因子,例如在基数 14 中,您检查 2 和 7 而不是 2 和 5)
现在剩下要做的就是找出我们在非终止/重复分数的情况下要做什么。
现在这是超级数论,所以我将把算法留给你,让你决定是否要在mathforum.org 或wolfram alpha 上了解更多信息
现在我们可以很容易地判断一个分数是否会终止,如果不是,那么它的重复数字循环的长度是多少。现在剩下要做的就是找到循环或它将从多少位开始。
在寻找有效算法的过程中,我在https://softwareengineering.stackexchange.com/ 上发现了这篇文章,应该会有所帮助。
some great insight - "当一个 (m,n)=1 的有理数 m/n 展开时,周期从 s 项开始,长度为 t,其中 s 和 t 是满足的最小数
10^s=10^(s+t) (mod n)。 "
所以我们需要做的就是找到 s 和 t:
def length_of_cycle(denominator):
mods = {}
for i in range(denominator):
key = 10**i % denominator
if key in mods:
return [ mods[key], i ]
else:
mods[ key ] = i
让我们生成展开的数字
def expasionGenerator( numerator, denominator ):
while numerator:
yield numerator // denominator
numerator = ( numerator % denominator ) * 10
现在要小心使用它,因为它会在重复扩展中创建一个无限循环(应该如此)。
现在我认为我们拥有编写函数的所有工具:
def the_expansion( numerator, denominator ):
# will return a list of two elements, the first is the expansion
# the second is the repeating digits afterwards
# the first element's first
integer_part = [ numerator // denominator ]
numerator %= denominator
if div_by_a_or_b( 2, 5, denominator ) and powers_of_only_2_or_5( denominator ):
return [ integer_part, [ n for n in expasionGenerator( numerator, denominator ) ][1:], [0] ]
# if it is not, then it is repeating
from itertools import islice
length_of_cycle = cycleLength( denominator )
generator = expasionGenerator( numerator*10, denominator )
# multiply by 10 since we want to skip the parts before the decimal place
list_of_expansion = [ n for n in islice(generator, length_of_cycle[0]) ]
list_of_repeating = [ n for n in islice(generator, length_of_cycle[1]) ]
return [ integer_part, list_of_expansion, list_of_repeating ]
现在剩下的就是打印它,这应该不会太糟糕。我将首先构建一个将数字列表转换为字符串的函数:
def listOfNumbersToString(the_list):
string = ""
for n in the_list:
string += str(n)
return string
然后创建转换函数:
def convert(numerator, denominator):
expansion = the_expansion(numerator,denominator)
expansion = [ listOfNumbersToString(ex) for ex in expansion ]
return expansion[0] + "." + expansion[1] + "(" + expansion[2] + ")"
在http://thestarman.pcministry.com/ 和一个类似的问题on stackoverflow 上阅读有关该主题的有趣文章