x86-64 Машинний код, 22 байти
48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
Вищеописані байти визначають функцію в 64-розрядному машинному коді x86, яка визначає, чи є вхідним значенням номер Chicken McNugget. Єдине додатне ціле число передається в ECX
регістр після 64-розрядного викликів Microsoft, який використовується в Windows. Результатом є булеве значення, повернене в EAX
реєстр.
Невикольована збірна мнемоніка:
; 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
Очевидно, що це грає дуже сильно відмінне від рішення Андерса Касеорга в Python , оскільки воно засноване на бітовому полі, що представляє значення, які є числами Курячого МакНуггет. Зокрема, кожен біт у цьому полі, що відповідає дійсному номеру Chicken McNugget, встановлюється рівним 1; всі інші біти встановлені на 0. (Це вважає 0 дійсним номером курячого МакНуггетта, але якщо вам це не подобається, вашим уподобанням є одномовна модифікація.)
Ми починаємо, просто завантаживши це значення в регістр. Це 64-бітове значення, для кодування якого вже потрібно 8 байт, плюс нам потрібен однобайтовий префікс REX.W, тому ми насправді досить витрачаємо в плані байтів, але це суть рішення. Я здогадуюсь того варто.
Потім переміщуємо поле право на вхідне значення. * Нарешті, ми маскуємо всі, окрім бітів нижчого порядку, і це стає нашим булевим результатом.
Однак, оскільки ви не можете змістити на більшу кількість бітів, фактично значущих, це працює лише для входів від 0–63. Для підтримки більш високих вхідних значень ми вставляємо тест у верхній частині функції, яка розгалужується на нижню частину вхідного значення -> = 64. Єдине, що цікаво в цьому, - ми попередньо завантажуємо константу бітового поля RAX
, а потім розгалужуємо вниз до інструкції, яка маскує біт нижнього порядку, забезпечуючи тим самим, що ми завжди повертаємо 1.
Спробуйте в Інтернеті!
(Виклик функції C там позначається атрибутом, який змушує GCC викликати його за допомогою правила виклику Microsoft, який використовує мій код складання. Якби TIO надав MSVC, це не було б необхідним.)
__
* В якості альтернативи зсуву ми могли б використовувати BT
інструкцію x86 , але це на 1 байт довше, щоб кодувати, тому переваги немає. Якщо тільки нас не змусили використовувати інший режим виклику, який не зручно передавати вхідне значення в ECX
регістр. Це буде проблемою, оскільки SHR
вимагає, щоб його вихідний операнд був CL
для динамічного підрахунку зсуву. Отже, інша умова виклику вимагає, щоб ми MOV
редагували вхідне значення з того регістра, в який воно було передане ECX
, що коштувало б нам 2 байти. BT
Команда може використовувати будь-який регістр в якості операнда - джерела, при вартості тільки 1 байт. Тож у цій ситуації було б краще.BT
ставить значення відповідного біта у прапор переносу (CF), тому ви використовуєтеSETC
інструкція отримати це значення в AL
цілому регістрі, як, щоб воно могло бути повернене абоненту.
Альтернативна реалізація, 23 байти
Ось альтернативна реалізація, яка використовує операції по модулю та множення, щоб визначити, чи є вхідним значенням номер Chicken McNugget.
Він використовує System V AMD64 convention , що передає вхідне значення в EDI
регістр. Результат все ще булевий, повернувся EAX
.
Зауважте, що на відміну від вищевказаного коду, це зворотний булевий (для зручності реалізації). Він повертається, false
якщо вхідним значенням є номер курячого Макнаггетта, або true
якщо вхідне значення не є номером Курячого МакНуггет.
; 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
Неприємно в цьому полягає в необхідності чітко обробляти вхідні значення> = 43 шляхом порівняння та розгалуження вгорі. Очевидно, існують й інші способи цього, які не потребують розгалуження, як алгоритм канадського коінхерінгахінга , але для кодування знадобиться набагато більше байтів, тому це не є розумним рішенням. Я думаю, що я, мабуть, пропускаю якийсь тріпоткий трюк, який би зробив цю роботу більш елегантною і матиме менше байтів, ніж рішення, що базується на бітфілді (оскільки кодування бітфілда займає стільки байтів), але я вивчив це для деякий час, і досі його не бачу.
Ну добре, спробуйте все- таки в Інтернеті !