Sie erhalten eine Maschine mit zwei 16-Bit-Registern x
und y
. Die Register werden initialisiert x=1
und y=0
. Die einzige Operation, die die Maschine ausführen kann, ist das Hinzufügen von Modulo 65536. Das heißt:
x+=y
-x
wird ersetzt durch(x + y) mod 65536
;y
ist unveränderty+=x
- ähnlich füry
x+=x
-x
wird ersetzt durch2x mod 65536
; legal nur wennx
es gerade isty+=y
- ähnlich füry
Das Ziel ist es, eine vorbestimmte Anzahl in einem der Register (entweder x
oder y
) zu erhalten.
Schreibe ein Programm oder ein Unterprogramm , das eine Reihe empfängt (in stdin
, argv
, Funktionsparameter Oberseite des Stapels oder einer anderen konventionellen Stelle), und gibt ein Programm diese Zahl zu erhalten. Die Ausgabe sollte an ein anderes herkömmliches Ausgabegerät gehen stdout
oder (falls Ihre Sprache keine hat stdout
) an ein anderes herkömmliches Ausgabegerät.
Das Ausgabeprogramm kann bis zu 100% plus 2 Schritte weit vom Optimum entfernt sein. Das heißt, wenn das kürzeste Programm zum Abrufen der Zielnummer n
Schritte enthält, kann Ihre Lösung nicht länger sein als 2n+2
. Diese Einschränkung dient dazu, "zu einfache" Lösungen (z. B. Zählen von 1, 2, 3, ...) zu vermeiden, erfordert jedoch keine vollständige Optimierung. Ich gehe davon aus, dass das kürzeste Programm am einfachsten zu finden ist, kann aber nicht sicher sein ...
Zum Beispiel: Eingabe = 25. Ausgabe:
y+=x
x+=y
x+=y
x+=x
x+=x
x+=x
y+=x
Ein weiteres Beispiel: Für jede Fibonacci-Zahl hat die Ausgabe dieses Wechselmuster. Für Eingabe = 21 ist Ausgabe
y+=x
x+=y
y+=x
x+=y
y+=x
x+=y
y+=x
Der kürzeste Code (gemessen in Bytes) gewinnt.
(Dieses Puzzle wurde von einem Code für einen 16-Bit-Prozessor inspiriert, den ich kürzlich generieren musste.)
PS Ich frage mich - für welche Nummer ist das optimale Programm am längsten?
quelle
x+=x
nur legal, wennx
es gerade ist? Auch für das kürzeste Programm denke ich, dass so etwas wie BFS funktionieren könnte.x+=x
nur für geradex
s funktioniert, wie kommt es, dass das beispiel für eine eingabe von 25 3 verdoppelt?Antworten:
CJam, 31
Wie @Tobia ‚s Antwort, mein Algorithmus auch schamlos
gestohleninspiriert @CChak die Antwort‘. Mit der schwarzen Magie von CJam gelang es mir jedoch, den Algorithmus noch kleiner zu implementieren.Probieren Sie es hier aus.
Golf gespielt:
Ungolfed:
Bitte korrigieren Sie mich, wenn ich falsch liege, aber ich dachte, dass die Modulo 65536-Operation, die in Antworten mit einem ähnlichen Algorithmus verwendet wird, nicht erforderlich ist. Ich habe die Frage so interpretiert, dass wir davon ausgehen können, dass die Eingabe eine gültige 16-Bit-Ganzzahl ohne Vorzeichen ist, und dass alle Zwischenwerte oder Ergebnisse dieses Algorithmus dies auch sein werden.
quelle
Perl
10797Erster Beitrag, also hier geht's.
Dies entspricht allen Kriterien für das Hinzufügen von Registern, aber ich habe nicht vollständig überprüft, ob meine Antwort immer innerhalb von 2n + 2 der optimalen Anzahl von Schritten lag. Für jede Fibonacci-Zahl liegt es jedoch deutlich innerhalb des Grenzwerts.
Hier ist eine detailliertere Aufschlüsselung
Wie ich bereits erwähnte, ist dies mein erster Versuch, Golf zu spielen. Ich bin mir also sicher, dass dies verbessert werden kann. Ich bin mir auch nicht sicher, ob der anfängliche Unterprogrammaufruf in einem rekursiven Aufruf gezählt werden muss oder nicht, was uns ein paar Zeichen in die Höhe treiben könnte.
Interessanterweise können wir den Code um 11 Byte * reduzieren und unsere "Effizienz" in Bezug auf die Anzahl der Registeroperationen verbessern, indem wir die Forderung lockern, dass nur gerade Werte "verdoppelt" werden können. Ich habe das zum Spaß hier aufgenommen:
Nachtrag beginnen:
Hat mir sehr gut gefallen, und ich habe in den letzten Wochen immer wieder damit herumgespielt. Dachte ich würde meine Ergebnisse posten.
Einige Zahlen:
Unter Verwendung eines BFS-Algorithmus, um eine optimale Lösung zu finden, gibt es in den ersten 2 ^ 16 Zahlen nur 18 Zahlen, die 23 Schritte erfordern. Dies sind: 58558, 59894, 60110, 61182, 61278, 62295, 62430, 62910, 63422, 63462, 63979, 64230, 64314, 4486, 64510, 64698, 64854, 65295.
Unter Verwendung des oben beschriebenen rekursiven Algorithmus ist die "am schwierigsten zu erreichende" Zahl 65535 bei 45 Operationen. (65534 dauert 44, und es gibt 14 Zahlen, die 43 Schritte benötigen) 65535 ist auch die größte Abweichung vom Optimum, 45 vs 22. Die Differenz von 23 Schritten beträgt 2n + 1. (Nur drei Zahlen treffen auf 2n: 65534, 32767, 32751.) Mit Ausnahme der trivialen (Null-Schritt-) Fälle über den definierten Bereich ergibt die rekursive Methode einen Durchschnitt von ungefähr dem 1,4-fachen der optimalen Lösung.
Fazit: Für die Zahlen 1-2 ^ 16 überschreitet der rekursive Algorithmus niemals den definierten Schwellenwert von 2n + 2, sodass die Antwort gültig ist. Ich vermute jedoch, dass es zu weit von der optimalen Lösung für größere Register / mehr Bits abweichen würde.
Der Code, den ich zum Erstellen des BFS verwendet habe, war schlampig, speicherintensiv, nicht kommentiert und absichtlich nicht enthalten. Also ... Sie müssen meinen Ergebnissen nicht vertrauen, aber ich bin ziemlich zuversichtlich.
quelle
Python 3, 202 Bytes
(Danke an @rationalis für ein paar Bytes)
Hier ist eine sehr einfache Lösung. Ich wünschte, ich könnte die letzte Linie besser spielen, aber mir fehlen momentan die Ideen. Mit anrufen
S(25)
.Das Programm führt nur ein einfaches BFS ohne Zwischenspeicherung aus, ist also sehr langsam. Hier ist
S(97)
für einige Beispielausgaben:quelle
Dyalog APL, 49 Zeichen / Byte *
Algorithmus schamlos inspiriert von @CChaks Antwort.
Beispiel:
Ungolfed:
* Dyalog APL unterstützt einen älteren Zeichensatz, bei dem die APL-Symbole den oberen 128-Byte-Werten zugeordnet sind. Daher kann ein APL-Programm, das nur ASCII-Zeichen und APL-Symbole verwendet, als Byte == Zeichen betrachtet werden.
quelle
Python, 183
Ich kann nicht garantieren, dass dies innerhalb des 2x optimalen Programms für gerade Zahlen bleibt, aber es ist effizient. Für alle gültigen Eingaben
0 <= n < 65536
erfolgt dies im Wesentlichen sofort und es wird ein Programm mit höchstens 33 Anweisungen erstellt. Für eine beliebige Registergrößen
(nach dem Fixieren dieser Konstante) würde esO(n)
mit höchstens2n+1
Befehlen einige Zeit dauern .Eine binäre Logik
Jede ungerade Zahl
n
kann in 31 Schritten erreicht werden: doy+=x
, immerx,y = 1,1
, und dann immer wieder zu verdoppelnx
mitx+=x
(für die erste Verdoppelung tunx+=y
, dax
ungerade zu beginnen).x
Auf diese Weise wird jede Potenz von 2 erreicht (es ist nur eine Linksverschiebung), und Sie können jedes Bity
auf 1 setzen, indem Sie die entsprechende Potenz von 2 addieren. Da wir 16-Bit-Register verwenden, und jedes Bit mit Ausnahme von für das erste braucht man eine Verdopplung, um zu erreichen und einey+=x
zu setzen, wir bekommen maximal 31 Ops.Jede gerade Zahl
n
ist nur eine Potenz von 2, nenne esa
mal eine ungerade Zahl, nenne esm
; dhn = 2^a * m
oder gleichwertign = m << a
. Verwenden Sie den obigen Prozess, um zu erhaltenm
, und setzen Sie ihn dann zurück,x
indem Sie ihn nach links verschieben, bis er 0 ist.x+=y
Setzen Sie ax = m
, und verdoppeln Sie dann, wenn Siex
zum ersten Malx+=y
und anschließend verwendenx+=x
.Was auch immer
a
ist, es braucht16-a
Schichtenx
, um zu kommeny=m
und zusätzlichea
Schichten, um zurückgesetzt zu werdenx=0
. Weiterea
Verschiebungen vonx
werden danach auftretenx=m
. Es werden also insgesamt16+a
Schichten verwendet. Es gibt bis zu16-a
Bits, die gesetzt werden müssen, um zu erhaltenm
, und jeder von ihnen benötigt einesy+=x
. Zum Schluss brauchen wir noch einen zusätzlichen Schrittx=0
, um mx+=y
,. Es dauert also höchstens 33 Schritte, um eine gerade Zahl zu erhalten.Sie können dies natürlich auf ein beliebiges Größenregister verallgemeinern. In diesem Fall werden für Ganzzahlen mit ungeraden und geraden Bits immer höchstens
2n-1
und2n+1
ops verwendetn
.Optimalität
Dieser Algorithmus erzeugt ein Programm , das nahezu optimal ist (dh innerhalb
2n+2
wennn
ist die minimale Anzahl von Schritten) für ungerade Zahlen. Wenn für eine gegebene ungerade Zahln
dasm
th-Bit die führende 1 ist, unternimmt jedes Programm mindestensm
Schritte, um zux=n
oder zu gelangeny=n
, da die Operation, die die Werte der Register am schnellsten erhöht,x+=x
odery+=y
(dh Verdopplungen) ist und es dauertm
Verdopplungen , um zu gelangen dasm
th-Bit von 1. Da dieser Algorithmus höchstens2m
Schritte benötigt (höchstens zwei pro Verdopplung, einer für die Verschiebung und einery+=x
), wird jede ungerade Zahl nahezu optimal dargestellt.Gerade Zahlen sind nicht ganz so gut, da immer 16 Operationen zum Zurücksetzen verwendet werden
x
, und 8 zum Beispiel in 5 Schritten erreicht werden können.Interessanterweise wird der obige Algorithmus überhaupt nicht verwendet
y+=y
, da ery
immer ungerade ist. In diesem Fall wird möglicherweise das kürzeste Programm für den eingeschränkten Satz von nur 3 Operationen gefunden.Testen
Ich habe einen einfachen Test geschrieben, um zu überprüfen, ob meine Lösung tatsächlich für alle gültigen Eingaben (
0 <= n < 65536
) korrekte Ergebnisse liefert und nie mehr als 33 Schritte durchläuft .Außerdem habe ich versucht, eine empirische Analyse durchzuführen, um die Ausgabe meiner Lösung mit den optimalen Ausgaben zu vergleichen. Es hat sich jedoch herausgestellt, dass die Breitensuche zu ineffizient ist, um die minimale Ausgabelänge für jede gültige Eingabe zu ermitteln
n
. Die Verwendung von BFS zum Ermitteln der Ausgabe fürn = 65535
wird beispielsweise nicht in angemessener Zeit beendet. Trotzdem bin ichbfs()
offen für Vorschläge.Ich habe jedoch meine eigene Lösung gegen @ CChak's getestet (implementiert in Python hier als
U
). Ich habe damit gerechnet, dass sich meine Leistung verschlechtern würde, da sie für kleinere gerade Zahlen drastisch ineffizient ist, aber über den gesamten Bereich auf zwei Arten gemittelt wird. Meine Leistung war durchschnittlich 10,8% bis 12,3% kürzer. Ich dachte, diesV
liege möglicherweise an der besseren Effizienz meiner eigenen Lösung für ungerade Zahlen. Daher wird meine für ungerade Zahlen und @ CChak für gerade Zahlen verwendet, liegt aberV
dazwischen (etwa 10% kürzer alsU
, 3% länger alsS
).quelle
x,y='xy'
es bis jetzt möglich war. Leider kann ich mir keine Möglichkeitc*b+e*2
vorstellen, mit der%
Formatierung kurz und bündig zu schreiben .S(2)
die Ausgabe wirklich lang?S(2)
wobei die kürzeste bei 19 ist). Ich verfolgex
undy
explizite nicht, so dass es, obwohl esx
nach dem zweiten Schritt 2 erreicht, trotzdem weiter aufx
0 zurückgesetzt wird . Ich habe das Gefühl, dass es eine bessere Lösung geben muss, aber bis jetzt fällt mir nichts ein einer.