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.
EDITest 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 CDQkullandığımız talimatın doğru çalışması için gereklidir .)
EAXArama 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+ POPkomutları ESI10'a başlatmak için yavaş ama kısa bir yol olarak kullanılır . Bu gereklidir, çünkü DIVx86'daki komut bir kayıt operand'ı gerektirir. (Derhal 10 gibi bir değere bölünen bir form yoktur.)
XORECXyazmacı 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, DIVişlecine EDX:EAXgöre bölen EAXve 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 ECXrakam) ve bölüm kalan kalan rakamdır.
CDQTalimat ayarı kısa yoludur EDXAslında 0'a oturum açma uzanır değeri EAXiçin EDX:EAXne, DIVtemettü olarak kullanır. Burada işaret genişletme CDQişlemine ihtiyacımız yok, çünkü giriş değeri işaretsiz, ancak XORtemizleme işleminin tersine EDX2 bayt olan 1 bayt.
- Sonra
DIVide EDX:EAXtarafından ESI(10).
- Kalan (
EDX) aküye ( ) eklenir ECX.
EAXRegister (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):
LEATalimat çarpma kısa yolu olarak kullanılır ECX2'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 LEAkomut daha hızlı ve daha tipiktir.)
- Daha sonra
CDQbölünmeye hazırlanmak için tekrar yaparız . Çünkü EAX(yani imzasız) pozitif olacaktır, bu sıfırlama etkisine sahiptir EDXhemen önce olduğu gibi.
- Bir sonraki bölüm, bu kez
EDX:EAXgiriş 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 EAXve EDX. Normalde MOVburada bir şeyler yaparsınız , ancak XCHGsadece 1 bayttır (yavaş da olsa). Çünkü EDXbö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, RETurn'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! :-)