x86-64-Maschinencode, 22 Byte
48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
Die obigen Bytes definieren eine Funktion im 64-Bit-x86-Maschinencode, die bestimmt, ob der Eingabewert eine Chicken McNugget-Nummer ist. Der einzelne positive Ganzzahlparameter wird im ECX
Register gemäß der unter Windows verwendeten 64-Bit-Aufrufkonvention von Microsoft übergeben. Das Ergebnis ist ein Boolescher Wert, der im EAX
Register zurückgegeben wird.
Ungolfed Assembler-Mnemonik:
; bool IsMcNuggetNumber(int n)
; n is passed in ECX
movabs rax, 0xFFFFF7DB6D349241 ; load a 64-bit constant (the bit field)
cmp ecx, 64
jge TheEnd ; if input value >= 64, branch to end
shr rax, cl
TheEnd:
and eax, 1 ; mask off all but LSB
ret
Offensichtlich spielt dies eine große Rolle für Anders Kaseorgs Lösung in Python , da es auf einem Bitfeld basiert, das die Werte darstellt, die Chicken McNugget-Zahlen sind. Insbesondere wird jedes Bit in diesem Feld, das einer gültigen Chicken McNugget-Nummer entspricht, auf 1 gesetzt. Alle anderen Bits werden auf 0 gesetzt. (Dies betrachtet 0 als eine gültige Chicken McNugget-Nummer. Wenn Ihnen das nicht gefällt, ist Ihre Präferenz eine Einzelbit-Modifikation entfernt.)
Wir beginnen damit, diesen Wert einfach in ein Register zu laden. Es ist ein 64-Bit-Wert, für dessen Codierung bereits 8 Byte erforderlich sind. Außerdem benötigen wir ein Ein-Byte-REX.W-Präfix, sodass wir tatsächlich einen erheblichen Verschwender-Aufwand in Bezug auf Bytes haben. Dies ist jedoch das Herzstück der Lösung Ich denke, es lohnt sich.
Dann verschieben wir das Feld um den Eingabewert nach rechts. * Schließlich maskieren wir alle außer dem niedrigsten Bit, und das wird unser boolesches Ergebnis.
Da Sie jedoch nicht mehr als die tatsächliche Anzahl von Bits im Wert verschieben können, funktioniert dies nur für Eingaben von 0 bis 63. Um eine höhere Eingabewerte zu unterstützen, legen wir einen Test an der Spitze der Funktion, die Zweige auf den Boden des Eingangswert> = 64. Das einzige , was interessant daran ist , die wir Vorspannung das Bit-Feld konstant RAX
, und dann Zweig bis auf den Befehl, der das Bit niedrigster Ordnung maskiert, wodurch sichergestellt wird, dass immer 1 zurückgegeben wird.
Probieren Sie es online!
(Der dortige C-Funktionsaufruf ist mit einem Attribut versehen, das bewirkt, dass GCC ihn gemäß der von meinem Assemblycode verwendeten Microsoft-Aufrufkonvention aufruft. Wenn TIO MSVC bereitgestellt hätte, wäre dies nicht erforderlich.)
__
* Als Alternative zu einer Verschiebung hätten wir den x86- BT
Befehl verwenden können, aber das ist 1 Byte länger für die Codierung, also kein Vorteil. Es sei denn, wir mussten eine andere Aufrufkonvention verwenden, die den Eingabewert im ECX
Register nicht bequem übergab . Dies wäre ein Problem, da sein Quelloperand für eine dynamische Verschiebungszählung SHR
erforderlich istCL
. Daher würde eine andere Aufrufkonvention erfordern, dass wir MOV
den Eingabewert von jedem Register, an das er übergeben wurde, editieren ECX
, was uns 2 Bytes kosten würde. Der BT
Befehl kann ein beliebiges Register als Quelloperand verwenden, und das zu einem Preis von nur 1 Byte. In dieser Situation wäre es also vorzuziehen.BT
Setzt den Wert des entsprechenden Bits in das Übertragsflag (CF), so dass Sie einen SETC
Befehl verwenden würden, um diesen Wert in einem Ganzzahlregister abzurufen, AL
so dass er an den Aufrufer zurückgegeben werden könnte.
Alternative Implementierung, 23 Bytes
Hier ist eine alternative Implementierung, die Modulo- und Multiplikationsoperationen verwendet, um zu bestimmen, ob der Eingabewert eine Chicken McNugget-Zahl ist.
Es verwendet die AMD64-Aufrufkonvention von System V , die den Eingabewert im EDI
Register übergibt . Das Ergebnis ist immer noch ein Boolescher Wert, der in zurückgegeben wird EAX
.
Beachten Sie jedoch, dass dies im Gegensatz zum obigen Code ein inverser Boolescher Wert ist (zur Vereinfachung der Implementierung). Es wird zurückgegeben, false
wenn der Eingabewert eine Chicken McNugget-Nummer ist oder true
wenn der Eingabewert keine Chicken McNugget-Nummer ist.
; bool IsNotMcNuggetNumber(int n)
; n is passed in EDI
8D 04 3F lea eax, [rdi+rdi*1] ; multiply input by 2, and put result in EAX
83 FF 2B cmp edi, 43
7D 0E jge TheEnd ; everything >= 43 is a McNugget number
99 cdq ; zero EDX in only 1 byte
6A 03 push 3
59 pop rcx ; short way to put 3 in ECX for DIV
F7 F1 div ecx ; divide input value by 3
6B D2 14 imul edx, edx, 20 ; multiply remainder of division by 20
39 D7 cmp edi, edx
0F 9C C0 setl al ; AL = (original input) < (input % 3 * 20)
TheEnd:
C3 ret
Das Hässliche daran ist, dass Eingabewerte> = 43 explizit von einem Vergleichs- und Verzweigungspunkt oben behandelt werden müssen. Es gibt natürlich auch andere Möglichkeiten, die keine Verzweigung erfordern, z. B. den Algorithmus von Caird Coinheringaahing. Die Codierung würde jedoch viel mehr Bytes in Anspruch nehmen. Dies ist also keine vernünftige Lösung. Ich vermisse wahrscheinlich einen Bit-Twiddling-Trick, der dazu führen würde, dass dies eleganter abläuft und weniger Bytes enthält als die obige bitfeldbasierte Lösung (da das Codieren des Bitfelds selbst so viele Bytes erfordert), aber ich habe dies untersucht eine Weile und kann es immer noch nicht sehen.
Na ja, versuchen Sie es online !