Periode der Dezimaldarstellung


16

Schreiben Sie eine Funktion, die eine einzelne positive ganze Zahl n annimmt und die Periode der Dezimaldarstellung von 1 / n zurückgibt .

Testfälle:

1 -> 1               # 1/1 = 1.0000...... = 1._0
2 -> 1               # 1/2 = 0.5000...... = 0.5_0
3 -> 1               # 1/3 = 0.3333...... = 0._3
7 -> 6               # 1/7 = 0.14285714.. = 0._142857
13 -> 6
14 -> 6
123 -> 5
345 -> 22
654 -> 108
12345 -> 822
67890 -> 120

Das ist . Eingebaute oder Bibliotheken, die den Zeitraum direkt zurückgeben, sind nicht zulässig. Nummern bis zu mindestens 100000 sollten in angemessener Zeit (höchstens einige Minuten) funktionieren.


Die Frage besagt, dass "Zahlen bis zu mindestens 100000 in angemessener Zeit funktionieren sollten", aber muss das Programm die richtige Antwort für größere Zahlen geben ? Oder wäre es akzeptabel, einen Algorithmus zu verwenden, der nur bis zu 100000 genau ist?
FireFly

1
@FireFly Algorithmen müssen die richtige Antwort liefern.
Howard

2
Warum würde ich 1 zurückgeben? Ich würde denken, 0?
Timtech

@ Timtech1.00000000000000000000000000000000000
Cruncher

@Cruncher Oh danke, ich verstehe es jetzt.
Timtech

Antworten:


11

APL, 19 Zeichen / Byte *

{(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}

Nars2000 . Die vorherige Version war bei einigen Nummern falsch, dies sollte richtig sein. Ich habe es manuell auf allen Nummern bis zu 50 überprüft.

Auch hier gebührt Ben Reich die Ehre, sich mit der Zeit auseinanderzusetzen10^i (mod x)

Explosionszeichnung

{                     ⍳⍵}   generate all naturals up to the argument ⍵
                 10x*       raise 10 to each of them, with unlimited precision
              ⍵|            compute the respective remainders mod ⍵
            ⌽               reverse the list
 (  ⍳⍨    )                 (fork) find the position of the first occurrence
  ↑                         of the fist element of the list
       1∘↓                  in the remainder of the list

Beispiele

      {(↑⍳⍨1∘↓)⌽⍵|10x*⍳⍵}¨1 2 3 7 13 14 123 345 654 12345 67890
1 1 1 6 6 6 5 22 108 822 120

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯ *: APL kann in einem eigenen (Legacy-) Einzelbyte -Zeichensatz geschrieben werden, der APL-Symbole den oberen 128-Byte-Werten zuordnet
. Aus diesem Grund kann ein Programm mit N Zeichen , das nur ASCII-Zeichen und APL-Symbole verwendet, als N Byte lang betrachtet werden.


Ich kann zB für Eingaben nicht die richtige Antwort bekommen 20. Können Sie das bitte überprüfen?
Howard

Ich bin den Beispielen gefolgt, die Sie gepostet haben. In Ihrem Beispiel ist 1/2 = 0,5 -> 1, also natürlich 1/20 = 0,05 -> 2. Was bekommen Sie?
Tobia

Die richtige Antwort wäre 1, da 1/20 = 0.05_0_.
Howard

Aha. Gib mir ein bisschen, ich werde meine Antwort überarbeiten.
Tobia

4scheint, dass es auch die falsche Antwort geben würde, weil 10 != 100 (mod 4).
Peter Taylor

7

GolfScript ( 42 27)

{:x)1\[{.10*x%}*]-1%(?)}:P;

Benchmark-Zeit: 5 Sekunden Benchmarking-Code:

'"The time is #{Time.now#1
}"'~ puts
[1 2 3 7 13 14 123 345 654 12345 67890 99991]{[P]p}%
'"The time is #{Time.now#2
}"'~ puts

Wir danken Ben Reich für die Kernidee, die Periode von zu betrachten 10^i (mod x).

Erläuterung

Die Periode pist definiert als die kleinste positive ganze Zahl, die iwir für alle ausreichend großen haben frac(10^i * 1/x) = frac(10^(i+p) * 1/x). Wir können das etwas vereinfachen frac(10^i / x) = frac(10^(i+p) / x). Nun, frac(a / x) = frac(b / x)genau dann , wenn a == b (mod x), so dass wir für die kleinste positive ganze Zahl , so suchen , dass für alle hinreichend großen i: 10^i == 10^(i+p) (mod x).

Angenommen 10^i == 10^(i+p) (mod x). Dann 10^(i+1) == 10 * 10^i == 10 * 10^(i+p) == 10^(i+p+1) (mod x); Sobald wir also eine Wiederholung bekommen, befinden wir uns in einem unzerbrechlichen Zyklus.

Es gibt nur xunterschiedliche Werte (mod x), so dass wir nach dem Taubenschlagprinzip eine Wiederholung in den ersten x + 1Werten von erhalten müssen 10^i (mod x).

Der obige Code berechnet also die x + 2Werte von 10^i (mod x)*. Dann ist die letzte garantiert eine Wiederholung, und indem ich die Liste umdrehe und danach suche, kann ich das jüngste Vorkommen finden. Darüber hinaus ist dies pseudolineare Zeit, da ich nur die eine Suche durchführe.

* Die Extra ist der Sonderfall zu behandeln x = 1, weil ich nicht reduzieren 10^0 (mod x)für ein und so suchen würde ich mich 0in [1].


Genial! Ich habe meine Antwort seit einer besseren Lösung gelöscht! -
Ben Reich

7

Golfscript - 26 Bytes

{:i.)+.,{;10*i%.}%i>|,}:f;

Bearbeiten: aktualisiert, um auszugeben, 1wenn die Dezimalstelle endet, anstatt die Länge der Dezimalstellendarstellung.

Eine ziemlich effiziente Version. Der Wert 67890 wird in ungefähr 10 Sekunden und 99991 in ungefähr 20 Sekunden ausgeführt. Es ist etwas langsamer als zuvor (ungefähr halb so schnell), da der Bereich, der iteriert wird, verdoppelt wurde, wobei die erste Hälfte ignoriert wird.

Alternativ auch 26 Bytes

{:i.)+.n*{*i%.}%i>)^^,}:f;

Dieser durchläuft die Zeichenfolge "\n"*(2*i+1), wobei ider Wert an die Funktion übergeben wird. Der Wert an den Block jedes Mal vergangen ist , der Ordnungswert "\n", das ist 10 .

Das )^^ist ein bisschen ein Workaround. Wenn Sie Uncons ein Zeichen aus einer Zeichenkette, ist das Ergebnis der Ordnungswert des Zeichens entfernt, wie oben erwähnt. Wenn Sie diesen Wert jedoch wieder anhängen, wird die Zeichenfolgendarstellung dieser Zahl angehängt und nicht das Zeichen - ziemlich unsymmetrisches Verhalten - und meiner Meinung nach ein Konstruktionsfehler. Wenn Sie das tatsächlich tun wollten, würde das erste Zeichenfolgen nur ein Byte kosten.

Eine zusätzliche Kopie des endgültigen Werts befindet sich bereits auf dem Stapel. )Daher entferne ich den endgültigen Wert erneut , xoder mit der Zeichenfolge und xoder erneut, sodass alle Zeichen, die vom ersten xoder hinzugefügt oder entfernt wurden, wiederhergestellt werden. Wenn int op stringals Zeichen statt als Zeichenfolgendarstellung behandelt würde, )^^könnte dies durch ersetzt werden |.

Beachten Sie, dass während Strings (die in Golfscript als Array von Ints gespeichert sind) den Wert jedes Zeichens mod 256 anzeigen , die Werte jedes Zeichens selbst möglicherweise außerhalb dieses Bereichs liegen. Beim Testen auf Eindeutigkeit (über festgelegte Operationen) oder Eindeutigkeit (über) ?wird der tatsächliche Wert verglichen und nicht der Anzeigewert.

Eine Patch-Datei für den aktuellen Golfscript-Interpreter :

61c61
<       to_gs
---
>       Gstring.new([self])

Das Obige wirkt sich nur auf das Verhalten von string op int(und umgekehrt) aus, wo opeines davon ist
+-|&^. Alles andere bleibt unberührt, auch das Verhalten von Gint`.

Die folgende 24-Byte- Lösung wird dann gültig:

{:i.)+.n*{*i%.}%i>|,}:f;

Und das behebt auch viele andere wirklich hässliche Workarounds .


Python - 48 Bytes

f=lambda n:len(set(10**-~i%n for i in range(n)))

Nicht die effizienteste Lösung, aber für Werte unter 100000 angemessen .

FWIW, das Kernelement ist identisch mit meiner Lösung zum Generieren zyklischer Zahlen in Dezimalzahl .

Eine effizientere Version desselben Codes ( 70 Byte ):

 def f(n):
  a=[];i=10%n
  while i not in a:a+=i,;i=i*10%n
  return len(a)

Der Wert 99991 dauert weniger als eine Sekunde.


@ PeterTaylor es ist ordas Array auf eine leere Zeichenfolge. Da es sich um eine festgelegte Operation handelt, werden alle Duplikate zuvor entfernt.
Primo

Aber woher kommt der leere String? Wenn die Funktion in sich abgeschlossen sein soll, müssen Sie ein zusätzliches Byte ausgeben und es erstellen .|.
Peter Taylor

1
@ PeterTaylor behoben .
Primo

1
Das Ändern des Verhaltens von string int +würde viele Programme zum Absturz bringen. Ich bin mir nicht sicher, wie oft die anderen Ops für dieses Typpaar verwendet werden.
Peter Taylor

@PeterTaylor Ich stimme zu, es würde. Aber bedenken Sie : convert int zu char: []+''+vs ''+. Anfügen int, wie char, string: []++vs +. Apend int, als String - Darstellung, um string: +vs `+. In seiner aktuellen Implementierung int''+ist das synonym zu int`, was angesichts der Ausführlichkeit, Array zu erzwingen, und dann zu einer Zeichenfolge zu erzwingen, wenn Sie das ASCII-Zeichen möchten, verschwenderisch erscheint.
Primo

3

GolfScript, 48 47 46

Vielen Dank an @PeterTaylor für das Abschneiden von zwei Zeichen.

{2{1$1$%!{.@\/\d}*}:d~;5d;9{2$%}{10*9+}/+,}:f;

Ich habe versucht, J zu verwenden, aber es brachte mir immer wieder seltsame Ergebnisse.

Online testen

Dies dividiert im Grunde genommen 2 und 5 durch die Zahl (2 und 5 sind die Primfaktoren von 10, und ihre Hin- und Herbewegungen enden und füllen den Algorithmus auf), dann die niedrigste ganze Zahl n, so dass die resultierende Zahl 10 ^ n - 1 dividiert die Periode.


3
Wenn Sie wissen, welches der erste Aufruf Ihrer Funktion sein wird, können Sie die Definition dort einfügen. Dh statt {...}:d;...dSie sparen 1 Zeichen mit...{...}:d~
Peter Taylor

@ PeterTaylor danke, hatte nicht daran gedacht
Volatility

1
Nachdem ich Ben kommentiert fhabe, dass er nicht auf dem Stapel bleibt, merke ich, dass du es auch tust. Sie sollten wirklich eine hinzufügen, ;um die Funktion für einen fairen Vergleich mit anderen Sprachen zu aktivieren.
Peter Taylor

2
Eine weitere Mikrooptimierung: int array ,)\;kann auf gekürzt werden int array +,.
Peter Taylor

2

Perl, 52 Zeichen

sub f{($p,%r)=1;1until$r{$p=$p*10%$_[0]}++;~~keys%r}

Dies ist eine unkomplizierte Umsetzung des direkten Ansatzes. (Glücklicherweise ist der direkte Ansatz auch ziemlich effizient: Dank Modulo-Arithmetik muss die Mathematik nie mehr als das Zehnfache des Eingabewerts verarbeiten.)

Da die Herausforderung eine Funktion spezifizierte, fühlte ich mich gezwungen, meine Variablen (neu) zu initialisieren, was ich für ein komplettes Programm nicht tun würde. Ebenso ist die ~~in der abschließenden Anweisung nicht erforderlich, wenn die Funktion sicher ist, dass sie in einem skalaren Kontext aufgerufen wird.


Probieren Sie die Eingabe dort aus, 20wo sie das falsche Ergebnis liefert.
Howard

2

Clojure, 102, 117, 115106

unformatiert:

(defn r([n](r{}(iterate #(mod(* % 10)n)10)0))([a[f & s]i](if(a f)(- i(a f))(recur(assoc a f i)s(inc i)))))

formatiert:

(defn r
  ([n] (r {} (iterate #(mod (* % 10) n) 10) 0))
  ([a [f & s] i]
    (if (a f)
      (- i (a f))
      (recur
        (assoc a f i)
        s
        (inc i)))))

Die Laufzeit skaliert mit der Periode. Fast sofort auf meinem Computer für die Beispielwerte.

Im Grunde berechnet dies das Ergebnis der Subtraktion nach jedem Schritt in der langen Division. Ein Zyklus wird erkannt, wenn diese Zahl an einem beliebigen Punkt mit der zuvor berechneten übereinstimmt.


Der Code bricht mit der Eingabe 20. Können Sie das bitte überprüfen?
Howard

Sie haben Recht, die oben genannte Lösung ist fehlerhaft. Mal sehen, ob ich das reparieren kann.
RedDeckWins

Was ist die erwartete Ausgabe für 20?
RedDeckWins

Die richtige Antwort wäre 1.
Howard


Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.