x86-64 Makine Kodu, 22 bayt
48 B8 41 92 34 6D DB F7 FF FF 83 F9 40 7D 03 48 D3 E8 83 E0 01 C3
Yukarıdaki baytlar, giriş değerinin bir Chicken McNugget numarası olup olmadığını belirleyen 64 bit x86 makine kodunda bir işlev tanımlar. Tekli pozitif tamsayı parametresi, Windows'ta kullanılan Microsoft 64 bit arama kuralınıECX
izleyerek kayıt defterine iletilir . Sonuç, kayıt defterinde döndürülen bir Boolean değeridir .EAX
Ungolfed montaj anımsatıcıları:
; 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
Açıkçası, bu, Anders Kaseorg'un Python'daki çözümünden büyük ölçüde etkilendiği için, Chicken McNugget sayıları olan değerleri temsil eden bir bit alanı üzerine kuruludur. Spesifik olarak, bu alandaki geçerli bir Chicken McNugget numarasına karşılık gelen her bir bit 1 olarak ayarlanır; diğer tüm bitler 0 olarak ayarlanır (Bu, 0 değerini geçerli bir Chicken McNugget numarası olarak kabul eder, ancak bundan hoşlanmıyorsanız tercihiniz uzaktaki tek bitlik bir değişikliktir.)
Bu değeri basitçe bir sicile yükleyerek başlıyoruz. Zaten kodlamak için 8 bayt alan 64 bitlik bir değer, artı bir baytlık REX.W ön ekine ihtiyacımız var, bu yüzden baytlar açısından gerçekten oldukça boşuna gidiyoruz, ama bu çözümün kalbi, yani Sanırım buna değer.
Daha sonra alanı giriş değeri ile sağa kaydırırız. * Sonunda, en düşük dereceli biti hariç hepsini gizleriz ve bu Boole sonucumuz olur.
Ancak, aslında değerdeki bit sayısından daha fazla kayma yapamadığınız için, bu yalnızca 0-63 arasındaki girişlerde işe yarar. Daha yüksek giriş değerlerini desteklemek için, giriş değerinin en altına dallanan fonksiyonun üstüne bir test ekleriz: = 64. Bu konuda ilginç olan tek şey bit alan sabitini önyüklememizdir , RAX
sonra dallanma en düşük sıradaki biti maskeleyen talimata kadar, böylece her zaman geri dönmemizi sağlayın 1.
Çevrimiçi deneyin!
(Oradaki C işlevi çağrısı, GCC'nin derleme kodumun kullandığı Microsoft çağrı kuralını kullanarak aramasına neden olan bir niteliğe açıklamalıdır. TIO MSVC sağlamışsa, bu gerekli olmaz.)
__
* Bir vardiyaya alternatif olarak, x86 BT
komutunu kullanabilirdik, ama kodlamak için 1 bayt daha uzun, bu yüzden avantaj yok. Biz edildi sürece zorla rahatlıkla giriş değerini geçemedi farklı bir arama kuralını kullanmayı ECX
kayıt. Bu bir problem olacaktır, çünkü kaynak işlenenin dinamik bir kayma sayımı için SHR
olmasını gerektirirCL
. Bu nedenle, farklı bir çağrı kuralı MOV
, giriş değerini, hangi kayıttan geçirildiyse ECX
girmemizi gerektirecek ve bu da bize 2 bayta mal olacaktır. BT
Talimat kullanabilirsiniz herhangi yalnızca 1 byte bir maliyetle, bir kaynak işlenen olarak kayıt. Yani, bu durumda, tercih edilir.BT
İlgili bitin değerini taşıma bayrağına (CF) koyar, böylece SETC
bu değeri bir tamsayı kaydında almak için bir talimat kullanırsınız, böylece AL
arayan kişiye geri döndürülebilir.
Alternatif uygulama, 23 bayt
Giriş değerinin bir Chicken McNugget numarası olup olmadığını belirlemek için modulo ve çarpma işlemlerini kullanan alternatif bir uygulama.
Kayıt defterindeki giriş değerini geçen System V AMD64 arama kuralını kullanır EDI
. Sonuç hala bir Boolean, geri döndü EAX
.
Bununla birlikte, yukarıdaki koddan farklı olarak, bunun ters bir Boole olduğuna dikkat edin (uygulama kolaylığı için). Bu döndüren false
giriş değeri bir tavuk McNugget sayı ise veya true
giriş değeri ise değil bir tavuk McNugget numarası.
; 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
Bu konuda çirkin olan şey, giriş değerlerinin> = 43 üstte bir karşılaştır ve dalla tarafından açıkça işlenmesi gereğidir. Açıkçası bunu yapmanın, caird coinheringaahing'in algoritması gibi dallanma gerektirmeyen başka yolları da var , ancak bu kodlamanın kodlaması çok daha fazla bayt alacaktır , bu yüzden makul bir çözüm değildir. Muhtemelen bu işi daha zarif bir şekilde halledecek ve yukarıdaki bitfield tabanlı çözümden daha az bayt olacak bir bit çırpma hilesi eksik olduğumu düşünüyorum (çünkü bit alanın kodlanması çok fazla bayt alır), ancak bunun için çalıştım. Bir süre ve hala göremiyorum.
Oh, yine de çevrimiçi deneyin !