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 EDIregistro, siguiendo la convención de llamada System V AMD64.
Inicialmente, se realiza una copia de este valor y se coloca en EAXpara que pueda devolverse si corresponde. ( LEAse usa en lugar de lo normal MOVporque necesitamos una instrucción con bytes impares).
Luego, el valor en EDIse 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 JNCinstrucció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 EAXse devuelve el valor original (in ).
Sin JNCembargo, hay un pequeño truco con la instrucción: ¡tiene un REPprefijo! Normalmente,REP prefijos solo se usan con instrucciones de cadena, pero como los manuales de Intel y AMD coinciden en que REPse 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, REPes 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 OUTinstrucció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 OUTinstrucció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 DXregistro (a través del CXregistro) en la parte superior del bucle, aunque esto solo es necesario si el valor es impar, para asegurar que la JNCinstrucción tenga un desplazamiento impar. Sin embargo, dado que lo que estamos omitiendo es la OUTinstrucció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.