x86-64 मशीन कोड, 24 बाइट्स
6A 0A 5E 31 C9 89 F8 99 F7 F6 01 D1 85 C0 75 F7 8D 04 09 99 F7 F7 92 C3
उपरोक्त कोड 64-बिट x86 मशीन कोड में एक फ़ंक्शन को परिभाषित करता है जो यह निर्धारित करता है कि इनपुट मान उसके अंकों के योग से दोगुना है या नहीं। फ़ंक्शन सिस्टम V AMD64 कॉलिंग कन्वेंशन के अनुरूप है, ताकि यह लगभग किसी भी भाषा से कॉल करने योग्य हो, जैसे कि यह एक सी फ़ंक्शन था।
यह EDIकॉलिंग कन्वेंशन के अनुसार, रजिस्टर के माध्यम से इनपुट के रूप में एकल पैरामीटर लेता है , जो परीक्षण करने के लिए पूर्णांक है। (यह एक सकारात्मक पूर्णांक माना जाता है , जो चुनौती के नियमों के अनुरूप है, और जो CDQनिर्देश हम सही ढंग से काम करने के लिए उपयोग करते हैं , उसके लिए आवश्यक है।)
यह EAXकॉलिंग कन्वेंशन के अनुसार, फिर से, रजिस्टर में अपना परिणाम देता है । परिणाम 0 होगा यदि इनपुट मान उसके अंकों के योग से विभाज्य था , और अन्यथा शून्य नहीं। (मूल रूप से, उलटा बूलियन, बिल्कुल चुनौती के नियमों में दिए गए उदाहरण की तरह।)
इसका सी प्रोटोटाइप होगा:
int DivisibleByDoubleSumOfDigits(int value);
यहाँ असंबद्ध असेंबली भाषा निर्देश दिए गए हैं, प्रत्येक निर्देश के उद्देश्य की संक्षिप्त व्याख्या के साथ एनोटेट किया गया है:
; 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
पहले ब्लॉक में, हम रजिस्टरों के कुछ प्रारंभिक आरंभ करते हैं:
PUSH+ POPनिर्देशों का उपयोग धीमी लेकिन संक्षिप्त विधि के रूप में किया जाता है ESI। इसे शुरू करने के लिए 10. यह आवश्यक है क्योंकि DIVx86 पर निर्देश के लिए एक रजिस्टर ऑपरेंड की आवश्यकता होती है। (कोई ऐसा रूप नहीं है, जो तत्काल मान से विभाजित हो, कहते हैं, 10.)
XORECXरजिस्टर को खाली करने के लिए एक छोटे और तेज तरीके के रूप में उपयोग किया जाता है । यह रजिस्टर आगामी लूप के अंदर "संचायक" के रूप में काम करेगा।
- अंत में, इनपुट मूल्य (से
EDI) की एक प्रति बनाई जाती है, और इसमें संग्रहीत किया जाता है EAX, जिसे हम लूप के माध्यम से जाने के रूप में देखा जाएगा।
फिर, हम लूपिंग शुरू करते हैं और इनपुट मूल्य में अंकों को जोड़ते हैं। यह x86 DIVइंस्ट्रक्शन पर आधारित है , जो EDX:EAXअपने ऑपरेंड से विभाजित होता है, और भागफल में EAXऔर शेष में रिटर्न करता है EDX। हम यहां क्या करेंगे इनपुट मान को 10 से विभाजित करते हैं, जैसे कि शेष अंतिम स्थान में अंक है (जो हम अपने संचायक रजिस्टर में जोड़ देंगे ECX), और भागफल शेष अंक है।
CDQशिक्षा की स्थापना की एक छोटी तरीका है EDX0. यह वास्तव में करने के लिए साइन-फैली में मूल्य EAXके लिए EDX:EAXहै, जो क्या है DIVलाभांश के रूप में उपयोग करता है। हमें वास्तव में यहां साइन-एक्सटेंशन की आवश्यकता नहीं है, क्योंकि इनपुट वैल्यू अहस्ताक्षरित है, लेकिन CDQ1 बाइट है, जैसा कि XORस्पष्ट उपयोग करने के लिए विरोध है EDX, जो 2 बाइट्स होगा।
- फिर हम
DIVआईडीई EDX:EAXद्वारा ESI(10)।
- शेष (
EDX) संचयकर्ता ( ECX) में जोड़ा जाता है ।
EAXरजिस्टर (भागफल) अगर यह 0. के बराबर है तो, हम इसे अंकों के सभी के माध्यम से किया है और हम के माध्यम से आता है तो यह देखने के लिए परीक्षण किया जाता है। यदि नहीं, तो हमारे पास योग करने के लिए अभी भी अधिक अंक हैं, इसलिए हम लूप के शीर्ष पर वापस जाते हैं।
अंत में, लूप समाप्त होने के बाद, हम लागू करते हैं number % ((sum_of_digits)*2):
LEAअनुदेश एक छोटी तरीके के रूप में प्रयोग किया जाता है गुणा करने के लिए ECX2 से (या, समतुल्य रूप, जोड़ने ECX(इस मामले में खुद के लिए), और परिणाम की दुकान एक अलग रजिस्टर में EAX)।
(हम भी कर सकते थे add ecx, ecx+ xchg ecx, eax, दोनों 3 बाइट्स हैं, लेकिन LEAनिर्देश तेज और अधिक विशिष्ट है।)
- फिर, हम
CDQफिर से विभाजन की तैयारी करते हैं। क्योंकि EAXसकारात्मक होगा (यानी, अहस्ताक्षरित), इस पर EDXपहले की तरह ही शून्यकरण का प्रभाव है ।
- अगला विभाजन है, इस बार
EDX:EAXइनपुट मान से विभाजित (एक अनमोल कॉपी जिसमें अभी भी रहता है EDI)। यह मोडुलो के बराबर है, जिसमें शेष है EDX। (भागफल भी डाला गया है EAX, लेकिन हमें इसकी आवश्यकता नहीं है।)
- अंत में, हम
XCHG(विनिमय) की सामग्री EAXऔर EDX। आम तौर पर, आप यहां करेंगे MOV, लेकिन XCHGकेवल 1 बाइट (यद्यपि धीमी) है। क्योंकि EDXविभाजन के बाद शेष रहता है, यह 0 होगा यदि मान समान रूप से विभाज्य या गैर-शून्य था अन्यथा। इस प्रकार, जब हम RETकलश करते हैं, EAX(परिणाम) 0 है यदि इनपुट मान को उसके अंकों के योग से दोगुना या गैर-शून्य से अन्यथा विभाजित किया गया था।
उम्मीद है कि स्पष्टीकरण के लिए पर्याप्त है।
यह सबसे छोटी प्रविष्टि नहीं है, लेकिन हे, ऐसा लग रहा है कि यह लगभग सभी गैर-गोल्फ भाषाओं में धड़कता है! :-)