Ich versuche, einen effizienten Algorithmus in Java zu finden, um den sich wiederholenden Dezimalteil von zwei Ganzzahlen zu finden a
und b
wo a/b
.
z.B. 5/7 = 0,714258 714258 ....
Ich kenne derzeit nur die Methode der langen Teilung.
Ich versuche, einen effizienten Algorithmus in Java zu finden, um den sich wiederholenden Dezimalteil von zwei Ganzzahlen zu finden a
und b
wo a/b
.
z.B. 5/7 = 0,714258 714258 ....
Ich kenne derzeit nur die Methode der langen Teilung.
Antworten:
Ich glaube, dass es hier zwei allgemeine Ansätze gibt, Sie können im Wesentlichen "Brute Force" nach der längsten sich wiederholenden Zeichenfolge suchen oder Sie können es als ein Problem der Zahlentheorie lösen.
Es ist lange her, dass ich auf dieses Problem gestoßen bin, aber ein Sonderfall (1 / n) ist Problem Nr. 26 in Project Euler, sodass Sie möglicherweise mehr Informationen finden, indem Sie nach effizienten Lösungen für diesen bestimmten Namen suchen. Eine Suche führt uns zu Eli Benderskys Website, auf der er seine Lösung erklärt . Hier ist ein Teil der Theorie von Mathworlds Decimal Expansions-Seite :
Jeder unregelmäßige Bruch
m/n
ist periodisch und hat einen von ihmlambda(n)
unabhängigen Zeitraumm
, der höchstensn-1
Ziffern lang ist. Wennn
es sich um eine Primzahl von 10 handelt, ist die Periodelambda(n)
vonm/n
ein Teiler vonphi(n)
und hat höchstensphi(n)
Ziffern, wobeiphi
es sich um die Totientenfunktion handelt. Es stellt sich heraus, dass dieslambda(n)
die multiplikative Ordnung von 10 (modn
) ist (Glaisher 1878, Lehmer 1941). Die Anzahl der Stellen im Wiederholungsteil der Dezimalerweiterung einer rationalen Zahl kann auch direkt aus der multiplikativen Reihenfolge ihres Nenners ermittelt werden.
Meine Zahlentheorie ist im Moment ein bisschen verrostet, also ist das Beste, was ich tun kann, Sie in diese Richtung zu lenken.
Lassen Sie n < d
, und Sie versuchen, den sich wiederholenden Teil von herauszufinden n/d
. Sei p
die Anzahl der Ziffern im Wiederholungsteil: dann n/d = R * 10^(-p) + R * 10^(-2p) + ... = R * ((10^-p)^1 + (10^-p)^2 + ...)
. Das Klammerteil ist eine geometrische Reihe, gleich 1/(10^p - 1)
.
Also n / d = R / (10^p - 1)
. Neu anordnen, um zu bekommen R = n * (10^p - 1) / d
. Um R zu finden, gehen Sie p
von 1 bis unendlich und halten Sie an, sobald Sie sich d
gleichmäßig geteilt haben n * (10^p - 1)
.
Hier ist eine Implementierung in 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
Verfolgt die Länge der Wiederholungssequenz, sodass Sie beispielsweise zwischen 1/9 und 1/99 unterscheiden können.)
Beachten Sie, dass diese Implementierung (ironischerweise) eine Endlosschleife ausführt, wenn die Dezimalerweiterung endlich ist, aber endet, wenn sie unendlich ist! Sie können diesen Fall jedoch überprüfen, da n/d
nur dann eine endliche Dezimaldarstellung d
vorliegt, wenn alle Primfaktoren , die nicht 2 oder 5 sind, auch in vorhanden sind n
.
0.123123... = 123/999
0.714258714258... = 714258/999999 (=5/7)
usw.
Lange Trennung? : /
Verwandeln Sie das Ergebnis in eine Zeichenfolge und wenden Sie diesen Algorithmus darauf an. Verwenden Sie BigDecimal, wenn Ihre Zeichenfolge bei normalen Typen nicht lang genug ist.