x86-64 Makine Kodu, 24 bayt
6A 0A 5E 31 C9 89 F8 99 F7 F6 01 D1 85 C0 75 F7 8D 04 09 99 F7 F7 92 C3
Yukarıdaki kod, 64-bit x86 kodunda, giriş değerinin rakamlarının toplamının iki katına bölünebilir olup olmadığını belirleyen bir işlevi tanımlar. İşlev, System V AMD64 çağrı kuralına uygundur, böylece tıpkı bir C işlevimiş gibi hemen hemen her dilden çağrılabilir.
EDI
Test edilecek tamsayı olan arama kuralına göre, yazmaç üzerinden giriş olarak tek bir parametre alır . (Bunun, meydan okuma kurallarına uygun, pozitif bir tamsayı olduğu varsayılır ve CDQ
kullandığımız talimatın doğru çalışması için gereklidir .)
EAX
Arama sözleşmesine göre, sonucunu kayıt defterinde tekrar verir. Girdi değeri , rakamlarının toplamı ile bölünebiliyorsa , sonuç 0 olur, aksi takdirde sıfır değildir. (Temel olarak, tam olarak kural kurallarında verilen örnekte olduğu gibi, ters bir Boolean.)
C prototipi şöyle olurdu:
int DivisibleByDoubleSumOfDigits(int value);
Her bir talimatın amacını kısa bir açıklama ile açıklanmış olan asılsız montaj dili talimatları şunlardır:
; EDI == input value
DivisibleByDoubleSumOfDigits:
push 10
pop rsi ; ESI <= 10
xor ecx, ecx ; ECX <= 0
mov eax, edi ; EAX <= EDI (make copy of input)
SumDigits:
cdq ; EDX <= 0
div esi ; EDX:EAX / 10
add ecx, edx ; ECX += remainder (EDX)
test eax, eax
jnz SumDigits ; loop while EAX != 0
lea eax, [rcx+rcx] ; EAX <= (ECX * 2)
cdq ; EDX <= 0
div edi ; EDX:EAX / input
xchg edx, eax ; put remainder (EDX) in EAX
ret ; return, with result in EAX
İlk blokta, bazı kayıtların ilk başlangıçlarını yaparız:
PUSH
+ POP
komutları ESI
10'a başlatmak için yavaş ama kısa bir yol olarak kullanılır . Bu gereklidir, çünkü DIV
x86'daki komut bir kayıt operand'ı gerektirir. (Derhal 10 gibi bir değere bölünen bir form yoktur.)
XOR
ECX
yazmacı temizlemek için kısa ve hızlı bir yol olarak kullanılır . Bu kayıt, gelecek döngünün içindeki "akümülatör" olarak görev yapacak.
- Son olarak, giriş değerinin bir kopyasından (from
EDI
) üretilir ve saklanır EAX
, ki bu döngüden geçerken gizlenir.
Ardından, girilen değerdeki ilmekleri ve rakamları toplamaya başlarız. Bu, DIV
işlecine EDX:EAX
göre bölen EAX
ve kalan kısmı içeri giren bölümü döndüren x86 komutuna dayanır EDX
. Burada yapacağımız şey, giriş değerini 10'a bölmek, kalanı en sondaki basamak (akümülatör kayıt defterimize ekleyeceğimiz ECX
rakam) ve bölüm kalan kalan rakamdır.
CDQ
Talimat ayarı kısa yoludur EDX
Aslında 0'a oturum açma uzanır değeri EAX
için EDX:EAX
ne, DIV
temettü olarak kullanır. Burada işaret genişletme CDQ
işlemine ihtiyacımız yok, çünkü giriş değeri işaretsiz, ancak XOR
temizleme işleminin tersine EDX
2 bayt olan 1 bayt.
- Sonra
DIV
ide EDX:EAX
tarafından ESI
(10).
- Kalan (
EDX
) aküye ( ) eklenir ECX
.
EAX
Register (bölüm) bu yüzden biz tüm basamakları bunu başardı ve biz yoluyla düşerse o 0'a eşit olup olmadığını görmek için test edilir. Değilse, toplayacağımız rakamların sayısı hala fazla olduğundan, döngünün tepesine geri dönüyoruz.
Son olarak, döngü bittikten sonra aşağıdakileri uygularız number % ((sum_of_digits)*2)
:
LEA
Talimat çarpma kısa yolu olarak kullanılır ECX
2'ye göre (eşit biçimde veya eklemek, ECX
(bu durumda farklı bir kayıtta kendisine) ve sonucunu saklamak EAX
).
(Ayrıca add ecx, ecx
+ yapabilirdik xchg ecx, eax
; ikisi de 3 bayttır, ancak LEA
komut daha hızlı ve daha tipiktir.)
- Daha sonra
CDQ
bölünmeye hazırlanmak için tekrar yaparız . Çünkü EAX
(yani imzasız) pozitif olacaktır, bu sıfırlama etkisine sahiptir EDX
hemen önce olduğu gibi.
- Bir sonraki bölüm, bu kez
EDX:EAX
giriş değerine bölünerek bölünmüş durumda EDI
. Bu, geri kalanı ile modulo eşdeğerdir EDX
. (Bölüm de belirtildi EAX
, ancak buna ihtiyacımız yok.)
- Son olarak,
XCHG
(değişim) içeriği EAX
ve EDX
. Normalde MOV
burada bir şeyler yaparsınız , ancak XCHG
sadece 1 bayttır (yavaş da olsa). Çünkü EDX
bölme işlemi içerir değeri eşit bölünebilen veya ise, bu 0 olacaktır, aksi takdirde sigara sıfır. Bu nedenle, RET
urn'da EAX
(sonuç), eğer giriş değeri, rakamlarının toplamı iki katına bölünebilirse veya sıfır değilse, 0 olur.
Umarım bu bir açıklama için yeterlidir.
Bu en kısa giriş değil, ama hey, neredeyse golf oynamayan dillerin hepsini geçiyor! :-)