Código de máquina x86-64, 22 bytes
48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
Los bytes anteriores definen una función en el código de máquina x86 de 64 bits que determina si el valor de entrada es un número Chicken McNugget. El parámetro entero positivo único se pasa en el ECXregistro, siguiendo la convención de llamadas de Microsoft de 64 bits utilizada en Windows. El resultado es un valor booleano devuelto en el EAXregistro.
Mnemónicos de ensamblaje sin golf:
; 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
Obviamente, esto juega mucho con la solución de Anders Kaseorg en Python , ya que se basa en un campo de bits que representa los valores que son números de Chicken McNugget. Específicamente, cada bit en este campo que corresponde a un número válido de Chicken McNugget se establece en 1; todos los demás bits se establecen en 0. (Esto considera que 0 es un número válido de Chicken McNugget, pero si no le gusta, su preferencia es una modificación de un solo bit).
Comenzamos simplemente cargando este valor en un registro. Es un valor de 64 bits, que ya requiere 8 bytes para codificar, además de que necesitamos un prefijo REX.W de un byte, por lo que realmente estamos siendo bastante derrochadores en términos de bytes, pero este es el corazón de la solución, por lo que Supongo que vale la pena.
Luego cambiamos el campo a la derecha por el valor de entrada. * Finalmente, enmascaramos todo excepto el bit de orden inferior, y ese se convierte en nuestro resultado booleano.
Sin embargo, dado que no puede cambiar más de la cantidad de bits realmente en el valor, esto solo funciona para entradas de 0 a 63. Para admitir valores de entrada más altos, insertamos una prueba en la parte superior de la función que se bifurca en la parte inferior del valor de entrada es> = 64. Lo único interesante de esto es que precargamos la constante del campo de bits RAXy luego se bifurca hasta la instrucción que enmascara el bit de orden más bajo, asegurando así que siempre devolvamos 1.
Pruébalo en línea!
(La llamada de función C allí está anotada con un atributo que hace que GCC lo llame usando la convención de llamadas de Microsoft que usa mi código de ensamblaje. Si TIO hubiera proporcionado MSVC, esto no sería necesario).
__
* Como alternativa a un cambio, podríamos haber usado la BTinstrucción x86 , pero eso es 1 byte más para codificar, por lo que no es una ventaja. A menos que nos veamos obligados a usar una convención de llamada diferente que no pasa convenientemente el valor de entrada en el ECXregistro. Esto sería un problema porque SHR requiere que su operando de origen sea CLpara un conteo de desplazamiento dinámico. Por lo tanto, una convención de llamada diferente requeriría que MOVeditemos el valor de entrada del registro al que se pasó ECX, lo que nos costaría 2 bytes. La BTinstrucción puede usar cualquier registro como operando de origen, a un costo de solo 1 byte. Entonces, en esa situación, sería preferible.BTcoloca el valor del bit correspondiente en el indicador de acarreo (CF), por lo que usaría una SETCinstrucción para obtener ese valor en un registro entero como ALpara que pueda devolverse al llamante.
Implementación alternativa, 23 bytes
Aquí hay una implementación alternativa que usa operaciones de módulo y multiplicación para determinar si el valor de entrada es un número Chicken McNugget.
Utiliza la convención de llamadas System V AMD64 , que pasa el valor de entrada en el EDIregistro. El resultado sigue siendo un booleano, devuelto en EAX.
Sin embargo, tenga en cuenta que, a diferencia del código anterior, este es un booleano inverso (por conveniencia de implementación). Devuelve falsesi el valor de entrada es un número de Chicken McNugget, o truesi el valor de entrada no es un número de Chicken McNugget.
; 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
Lo feo de esto es la necesidad de manejar explícitamente los valores de entrada> = 43 mediante una comparación y ramificación en la parte superior. Obviamente, hay otras formas de hacerlo que no requieren ramificación, como el algoritmo de caird coinheringaahing , pero esto requeriría muchos más bytes para codificar, por lo que no es una solución razonable. Supongo que probablemente me estoy perdiendo algún truco que hace que esto funcione de manera más elegante y tenga menos bytes que la solución basada en el campo de bits anterior (ya que codificar el campo de bits en sí toma tantos bytes), pero he estudiado esto para un rato y todavía no puedo verlo.
Oh, bueno, pruébalo en línea de todos modos