Машинный код x86-64, 22 байта
true
Приведенные выше байты определяют функцию в 64-битном машинном коде x86, которая определяет, является ли входное значение числом Чикен МакНаггет. Единственный положительный целочисленный параметр передается в false
register, following the Соглашение о 64-битных вызовах Microsoft используется в Windows. Результатом является логическое значение, возвращаемое в EAX
register.
Мнемоника сборки без гольфа:
EDI
Очевидно, это сильно влияет на Решение Андерса Касеорга на Python, поскольку оно основано на битовом поле, представляющем значения, являющиеся числами Чикен МакНаггет. В частности, каждый бит в этом поле, соответствующий допустимому номеру Чикен МакНаггет, установлен в 1; все остальные биты установлены в 0. (При этом 0 считается действительным числом Чикен МакНаггет, но если вам это не нравится, вы предпочитаете изменить однобитовое значение.)
Мы начнем с простой загрузки этого значения в регистр. Это 64-битное значение, для кодирования которого уже требуется 8 байт, плюс нам нужен однобайтовый префикс REX.W, поэтому мы действительно довольно расточительны с точки зрения байтов, но это суть решения, поэтому Я думаю, оно того стоит.
Затем мы сдвигаем поле вправо на входное значение.* Наконец, мы маскируем все, кроме младшего бита, и это становится нашим логическим результатом.
Однако, поскольку вы не можете сдвинуть значение больше, чем фактическое количество битов, это работает только для входных значений от 0 до 63. Чтобы поддерживать более высокие входные значения, мы вставляем тест вверху функции, который разветвляется до нижней части входного значения >= 64. Единственное, что интересно в этом, это то, что мы предварительная загрузка константа битового поля в AL
, and then branch down to the instruction that masks off the lowest-order bit, thus ensuring that we always return 1.
Попробуйте онлайн!
(Вызов функции C там аннотирован атрибутом, который заставляет GCC вызывать ее, используя соглашение о вызовах Microsoft, которое использует мой ассемблерный код. Если бы TIO предоставил MSVC, в этом не было бы необходимости.)
__
* В качестве альтернативы сдвигу мы могли бы использовать x86. SETC
instruction, but that's 1 byte longer to encode, so no advantage. Unless we were принужденный использовать другое соглашение о вызовах, которое не позволяет удобно передавать входное значение в BT
register. This would be a problem because BT
требует что его исходный операнд будет ECX
for a dynamic shift count. Therefore, a different calling convention would require that we MOV
отредактировал входное значение из любого регистра, в который оно было передано CL
, which would cost us 2 bytes. The SHR
инструкция может использовать любой зарегистрироваться в качестве исходного операнда, затрачивая всего 1 байт. Так что в такой ситуации это было бы предпочтительнее. ECX
puts the value of the corresponding bit into the carry flag (CF), so you would use a BT
инструкция для получения этого значения в целочисленном регистре, например RAX
so it could be returned to the caller.
Альтернативная реализация, 23 байта
Вот альтернативная реализация, которая использует операции по модулю и умножения, чтобы определить, является ли входное значение числом Чикен МакНаггет.
Он использует Соглашение о вызовах System V AMD64, который передает входное значение в ; 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
register. The result is still a Boolean, returned in EAX
.
Однако обратите внимание: в отличие от приведенного выше кода, это обратный Логическое значение (для удобства реализации). Он возвращает ECX
if the input value is a Chicken McNugget number, or 48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
если входное значение нет номер Чикен МакНаггет.
Inequality
Что некрасиво в этом, так это необходимость явно обрабатывать входные значения >= 43 с помощью сравнения и перехода вверху. Очевидно, есть и другие способы сделать это, не требующие ветвления, например Алгоритм Кэрда Коинхерингаахинга, но это займет много больше байтов для кодирования, поэтому это неразумное решение. Я полагаю, что мне, вероятно, не хватает какого-то трюка с битовым изменением, который сделал бы эту работу более элегантной и занимал бы меньше байтов, чем решение на основе битового поля, описанное выше (поскольку кодирование самого битового поля занимает очень много байтов), но я изучил это для какое-то время и до сих пор не вижу этого.
Ну что ж, попробуй онлайн в любом случае!