web-dev-qa-db-ja.com

繰り返し小数を見つける効率的な方法は何ですか

Javaで効率的なアルゴリズムを見つけようとしています。2つの整数abの繰り返しの小数部を見つけるためにa/b

例えば。 5/7 = 0.714258 714258 ...

私は現在、長除算法しか知りません。

24
Jun Hao

ここには2つの一般的なアプローチがあると思います。本質的に「ブルートフォース」で最長の繰り返し文字列を探すか、数論の問題として解くことができます。

私がこの問題に遭遇して久しぶりですが、特別なケース(1/n)はProject Eulerの問題#26なので、その特定の名前の効率的な解決策を検索することで、より多くの情報を見つけることができる場合があります。 1回の検索でEli BenderskyのWebサイトが表示され、彼は 彼の解決策 について説明します。 Mathworldの Decimal Expansionsページの理論の一部を以下に示します

非正規の小数_m/n_は周期的であり、mとは無関係のピリオドlambda(n)を持ちます。これは、最大_n-1_桁です。 nが10に比較的素数である場合、_m/n_のピリオドlambda(n)phi(n)の約数であり、最大でphi(n)桁です。ここで、phiはトーティエント関数です。 lambda(n)は10の 乗法次数 であることがわかります(mod n)(Glaisher 1878、Lehmer 1941) 。有理数の10進展開の繰り返し部分の桁数は、分母の乗数の次数から直接求めることもできます。

私の数論は今のところ少し錆びているので、私ができる最善のことはあなたをその方向に向けることです。

10
Daniel B

_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から無限大にループし、dn * (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進展開が有限の場合は永久にループしますが、無限の場合は終了します。ただし、_n/d_は、2または5以外のdのすべての素因数がnにも存在する場合に限り、有限の10進数表現を持つため、このケースを確認できます。

8
valtron

長割り? :/

結果を文字列に変換し、それに このアルゴリズム を適用します。文字列が通常の型で十分に長くない場合は、BigDecimalを使用します。

2
Robert Harvey