Código de máquina x86-64, 8 bytes
Inspirado en la solución de Bruce Forte , pero ligeramente por debajo del par. :-)
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
Se toma un único parámetro entero en el EDI
registro, siguiendo la convención de llamada System V AMD64.
Inicialmente, se realiza una copia de este valor y se coloca en EAX
para que pueda devolverse si corresponde. ( LEA
se usa en lugar de lo normal MOV
porque necesitamos una instrucción con bytes impares).
Luego, el valor en EDI
se desplaza a la derecha por 1, lo que coloca el bit desplazado en la bandera de acarreo (CF). Este bit será 0 si el número fue par o 1 si fue impar.
Luego probamos CF utilizando la JNC
instrucción, que se ramificará solo si CF es 0 (es decir, el número fue par). Esto significa que entraremos en un bucle infinito para valores pares. Para valores impares, caemos y EAX
se devuelve el valor original (in ).
Sin JNC
embargo, hay un pequeño truco con la instrucción: ¡tiene un REP
prefijo! Normalmente,REP
prefijos solo se usan con instrucciones de cadena, pero como los manuales de Intel y AMD coinciden en que REP
se ignoran los prefijos irrelevantes / superfluos / redundantes , arrojamos uno en la instrucción de bifurcación aquí para que tenga 3 bytes de longitud. De esa manera, el desplazamiento relativo que se codifica en la instrucción de salto también es impar. (Y, por supuesto, REP
es en sí mismo un prefijo de byte impar).
Gracias a dios RET
está codificado usando un byte extraño!
Pruébalo en línea!
En caso de que no piense que devolver el valor si es impar o entrar en un bucle infinito si es par (para que nunca regrese) satisfaga los requisitos de "salida" del desafío, o simplemente desea algo más interesante, aquí hay una función que genera el valor en un puerto serie (pero solo si es extraño, por supuesto).
Código de máquina x86-64 (salida al puerto serie), 17 bytes
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
Lo que hace que esto sea un poco más interesante es que el código hace más , lo que significa que fue más difícil hacerlo todo usando instrucciones que están codificadas usando solo bytes impares. Por supuesto, esto también significa que falla en el golf de código, por lo que es una especie de compensación: ¿desea interesante y desafiante, o quiere corto?
De todos modos, esto usa la OUT
instrucción x86 para escribir en el puerto de E / S 0x3F8, que es el puerto serie COM1 estándar en una PC. La parte divertida, por supuesto, es que todos los puertos de E / S estándar (serie y paralelo) tienen direcciones pares, por lo que no pueden codificarse como inmediatos para la OUT
instrucción o moverse directamente a un registro. Debe inicializar con uno menos que el valor real y luego incrementar el valor en el registro. También está limitado a usar ciertos registros para la manipulación porque necesita registros que están codificados usando bytes impares en la instrucción cuando se usan como operandos.
Además, tuve que inicializar el DX
registro (a través del CX
registro) en la parte superior del bucle, aunque esto solo es necesario si el valor es impar, para asegurar que la JNC
instrucción tenga un desplazamiento impar. Sin embargo, dado que lo que estamos omitiendo es la OUT
instrucción, todo lo que hace este código es desperdiciar ciclos y registrar registros de cero; en realidad no genera nada, por lo que no rompe las reglas.
Finalmente, esta función volverá (después de haber realizado o no la salida al puerto serie) con el valor de entrada restante EAX
. Pero eso en realidad no rompe ninguna regla; todas las funciones en lenguaje ensamblador regresarán con un valor en EAX
— la pregunta es si es un valor significativo o un valor basura . Eso está determinado por la documentación de la función (esencialmente, devuelve un valor o devuelve void
), y en este caso, lo estoy documentando como no devuelve un valor. :-)
No hay un enlace TIO para este, ya que no implementa la salida a los puertos serie. Necesitarás hierro real o imaginación.