查找重复小数的有效方法是什么


24

我试图在Java中找到一种有效的算法,以找到两个整数的重复小数部分a以及bwhere a/b

例如。5/7 = 0.714258 714258 ....

我目前只知道长除法。


2
因此,您有a = 5和b = 7,并且可以很容易地计算出浮点数的a / b,但是您想知道的是它在小数点后6位重复吗?
Sparr

Answers:


10

我相信这里有两种通用方法,您可以从本质上“蛮力”寻找最长的重复字符串,也可以将其作为数论问题解决。

自从我遇到这个问题已经很长时间了,但是特例(1 / n)是Euler项目上的问题26,因此您可以通过搜索该特定名称的有效解决方案来找到更多信息。一次搜索将我们带到Eli Bendersky的网站,他在那里解释了他的解决方案。这是Mathworld的“ 十进制展开”页面中的一些理论:

任何非规则分数m/n都是周期性的,并且具有lambda(n)独立于的周期,该周期m最多n-1 为数位。如果n是相对素10,则周期lambda(n)m/n是一个约数phi(n),并具有最高phi(n)的数字,其中phi是欧拉函数。事实证明,这lambda(n)是10(模)的乘法阶n(Glaisher 1878,Lehmer 1941)。有理数的十进制扩展的重复部分中的位数也可以直接从其分母的乘法顺序中找到。

目前,我的数论有点生锈,所以我能做的最好的就是将您指向那个方向。


8

让我们来n < d,您正在尝试找出的重复部分n/d。设p重复部分的位数:然后n/d = R * 10^(-p) + R * 10^(-2p) + ... = R * ((10^-p)^1 + (10^-p)^2 + ...)。方括号中的部分是一个几何级数,等于1/(10^p - 1)

这样n / d = R / (10^p - 1)。重新排列以获得R = n * (10^p - 1) / d。为了找到R,循环p从1到无穷大,并停止尽快d整除n * (10^p - 1)

这是Python中的实现:

def f(n, d):
    x = n * 9
    z = x
    k = 1
    while z % d:
        z = z * 10 + x
        k += 1
    return k, z / d

(例如,k跟踪重复序列的长度,因此您可以区分1/9和1/99)

请注意,如果十进制扩展名是有限的,则此实现(具有讽刺意味的是)永远循环,但如果无限扩展,则终止!不过,您可以检查这种情况,因为n/d如果的所有素数d都不是2或5,那么它也只有有限的十进制表示形式n


1
这个答案似乎是正确的。该方法是基于下面的“规则”:0.123123... = 123/999 0.714258714258... = 714258/999999 (=5/7)
来自

4
它无法通过1/6或5/12这样的案例:\
razpeitia

1
@razpeitia我做了类似的事情,但是在所有情况下都可以工作(包括整数除法)。检出:codepad.org/hKboFPd2
Tigran Saluev'17年

我做了类似@ TigranSaluev的一个JavaScript实现在github.com/Macil/cycle-division
Macil

2

长除法?:/

将结果转换为字符串,然后对其应用此算法。如果您的字符串对于普通类型不够长,请使用BigDecimal。


4
“将其转换为字符串”可能需要任意精度计算和一个很长的字符串才能计算出该字符串重复部分的两个副本(您怎么知道何时停止计算?.121212312121231212123 ...就是个问题)
Sparr

@Sparr重复的长度始终小于分母。

@MichaelT我没有意识到。如果为true,则精度不是精确的“任意”,而是取决于分母可以任意高。
Sparr 2013年


我认为您链接到的算法无需修改即可工作。它包括重叠的重复,并且在整个字符串中搜索(不仅限于连续匹配)。例如,“香蕉”中最长的重复子字符串是“安娜”。
Web_Designer
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.