x86-64-Maschinencode, 8 Byte
Inspiriert von Bruce Fortes Lösung , aber leicht unterdurchschnittlich. :-)
8D 07 lea eax, [rdi] ; put copy of input parameter in EAX
D1 EF shr edi, 1 ; shift LSB into CF
InfiniteLoop:
F3 73 FD rep jnc InfiniteLoop ; test CF; infinite loop back here if input was even
C3 ret ; return with original input in EAX if it was odd
Ein einzelner ganzzahliger Parameter wird EDI
gemäß der Aufrufkonvention von System V AMD64 in das Register aufgenommen.
Eine Kopie dieses Wertes wird anfangs erstellt und dort abgelegt, EAX
damit er gegebenenfalls zurückgegeben werden kann. ( LEA
Wird anstelle des normalen MOV
Befehls verwendet, da ein Befehl mit ungeraden Bytes benötigt wird.)
Dann wird der Wert in EDI
um 1 nach rechts verschoben, wodurch das verschobene Bit in das Übertragsflag (CF) gesetzt wird. Dieses Bit ist 0, wenn die Zahl gerade war, oder 1, wenn sie ungerade war.
Wir testen dann CF mit dem JNC
Befehl, der nur verzweigt, wenn CF 0 ist (dh die Zahl war gerade). Dies bedeutet, dass wir für gerade Werte in eine Endlosschleife gehen. Bei ungeraden Werten fallen wir durch und der ursprüngliche Wert (in EAX
) wird zurückgegeben.
Es gibt jedoch einen kleinen Trick mit der JNC
Anweisung - sie hat ein REP
Präfix! Normalerweise werden REP
Präfixe nur mit Zeichenfolgenanweisungen verwendet. Da jedoch in den Handbüchern von Intel und AMD die beiden übereinstimmen, dass irrelevante / überflüssige / redundante REP
Präfixe ignoriert werden, setzen wir hier einen in die Verzweigungsanweisung, um eine Länge von 3 Byte zu erzielen. Auf diese Weise ist auch der relative Versatz, der in der Sprunganweisung codiert wird, ungerade. (Und natürlich REP
ist es selbst ein Präfix für ungerade Bytes.)
Gott RET
sei Dank wird mit einem ungeraden Byte verschlüsselt!
Probieren Sie es online!
Für den Fall, dass Sie nicht glauben, den Wert zurückzugeben, wenn er ungerade ist, oder in eine Endlosschleife zu gehen, wenn er gerade ist (so dass Sie nie zurückkehren), um die "Ausgabe" -Anforderungen der Herausforderung zu erfüllen, oder wenn Sie nur etwas Interessanteres wollen, hier eine Funktion das gibt den Wert an eine serielle Schnittstelle aus (aber natürlich nur, wenn es ungerade ist).
x86-64-Maschinencode (Ausgabe an serielle Schnittstelle), 17 Byte
8D 07 lea eax, [rdi] ; put copy of input parameter (EDI) in EAX
B1 F7 mov cl, 0xf7 ; put 0xF7 into low-order bits of CX
B5 03 mov ch, 0x03 ; put 0x03 into high-order bits of CX
FE C1 inc cl ; increment low-order bits of CX to 0xF8 (so all together it's now 0x3F8)
0F B7 D1 movzx edx, cx ; move CX to DX ("MOV DX, CX" would have a 16-bit prefix of 0x66)
D1 EF shr edi, 1 ; shift LSB of input parameter into CF
73 01 jnc IsEven ; test CF: branch if 0 (even), fall through if 1 (odd)
EF out dx, eax ; output EAX (original input) to I/O port 0x3F8 (in DX)
IsEven:
C3 ret ; return
Was dies ein bisschen interessanter macht, ist, dass der Code mehr kann , was bedeutet, dass es schwieriger war, alles mit Befehlen zu machen, die nur mit ungeraden Bytes codiert sind. Das bedeutet natürlich auch, dass es beim Codegolf versagt. Es ist also eine Art Kompromiss - möchten Sie interessant und herausfordernd sein, oder möchten Sie sich kurz fassen?
In jedem Fall wird der x86- OUT
Befehl verwendet , um auf den E / A-Port 0x3F8 zu schreiben, der der standardmäßige serielle COM1-Port eines PCs ist. Der lustige Teil ist natürlich, dass alle Standard-E / A-Ports (seriell und parallel) gerade Adressen haben, sodass sie nicht einfach als Direktbefehle codiert OUT
oder direkt in ein Register verschoben werden können. Sie haben mit einer weniger als dem tatsächlichen Wert zu initialisieren, und dann erhöhen Sie den Wert in dem Register. Sie können auch nur bestimmte Register für die Manipulation verwenden, da Sie Register benötigen, die mit ungeraden Bytes in der Anweisung codiert sind, wenn sie als Operanden verwendet werden.
Außerdem musste ich das DX
Register (über das CX
Register) oben in der Schleife initialisieren , obwohl dies nur erforderlich ist, wenn der Wert ungerade ist, um sicherzustellen, dass der JNC
Befehl einen ungeraden Versatz hat. Da wir jedoch den OUT
Befehl überspringen , führt dieser Code nur zu Verschwendung von Zyklen und Registern zum Löschen von Daten. es nicht wirklich Ausgabe nichts, so dass er die Regeln nicht brechen.
Schließlich kehrt diese Funktion mit dem in belassenen Eingabewert zurück (nachdem die Ausgabe an die serielle Schnittstelle durchgeführt wurde oder nicht) EAX
. Aber das verstößt eigentlich nicht gegen Regeln; Alle Funktionen in der Assemblersprache werden mit einem Wert in zurückgegeben. Die EAX
Frage ist nur, ob es sich um einen signifikanten Wert oder einen Garbage- Wert handelt. void
Dies wird durch die Dokumentation der Funktion bestimmt (gibt sie im Wesentlichen einen Wert zurück oder gibt sie einen Wert zurück ), und in diesem Fall dokumentiere ich, dass sie keinen Wert zurückgibt. :-)
Keine TIO-Verbindung für diese, da keine Ausgabe an serielle Schnittstellen implementiert wird. Du brauchst echtes Eisen oder eine Fantasie.