回答:
ここには2つの一般的なアプローチがあると思います。基本的に「ブルートフォース」で最も長い繰り返し文字列を探すか、それを数論の問題として解決することができます。
私がこの問題に出くわしてから長い時間が経ちましたが、特別なケース(1 / n)はProject Eulerの問題#26であるため、その特定の名前の効率的な解決策を検索することでより多くの情報を見つけることができるかもしれません。1回の検索でEli BenderskyのWebサイトに移動し、そこで彼が解決策を説明します。MathworldのDecimal Expansionsページの理論の一部を次に示します。
非正規分数
m/n
は周期的であり、最大で 数字の長さであるからlambda(n)
独立した周期を持ちます。もしは、その後の期間、10と互いに素であるのの除数であると最大であり数字、トーティエント関数です。それは、10(mod )の乗法次数であることがわかります(Glaisher 1878、Lehmer 1941)。有理数の10進数展開の繰り返し部分の桁数は、その分母の乗数の順序から直接見つけることもできます。m
n-1
n
lambda(n)
m/n
phi(n)
phi(n)
phi
lambda(n)
n
私の数論は現時点では少し錆びているので、私ができる最善のことはその方向にあなたを向けることです。
みましょうn < d
、あなたはの繰り返し部分を理解しようとしていますn/d
。ましょうp
繰り返し部分の桁数:then 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を区別できます)
この実装は(皮肉なことに)10進展開が有限の場合は永久にループしますが、無限の場合は終了することに注意してください!ただし、2または5でないn/d
すべての素因数がに存在する場合のみ有限の10進表現を持つため、このケースを確認できます。d
n
0.123123... = 123/999
0.714258714258... = 714258/999999 (=5/7)
など
長い分裂?:/
結果を文字列に変換してから、このアルゴリズムを適用します。文字列が通常の型で十分に長くない場合は、BigDecimalを使用します。