x86 मशीन कोड, 34 बाइट्स
51
31 D2
AD
F7 D0
25 C0 C0 C0 00
75 01
42
E2 F3
C1 E2 03
DB 04 24
52
DB 04 24
DE F1
DB 1C 24
58
5A
C3
कोड के ये बाइट्स एक फ़ंक्शन को परिभाषित करते हैं जो बिटमैप इनपुट लेता है और एक पूर्णांक मान देता है जो इसके ओकटास को दर्शाता है। सी में के रूप में , सरणियों (जैसे बिटमैप) को पहले तत्व और एक आकार / लंबाई के लिए एक संकेतक के रूप में दर्शाया जाता है। इस प्रकार, यह फ़ंक्शन दो पैरामीटर लेता है: बिटमैप में पंक्तियों की कुल संख्या (पंक्तियाँ × कॉलम) और बिटमैप के लिए एक सूचक।
यह कोड एक कस्टम रजिस्टर-आधारित कॉलिंग कन्वेंशन का उपयोग करता है, जहां ESI
रजिस्टर में बिटमैप पॉइंटर को पास किया जाता है और बिटमैप का आकार ECX
रजिस्टर में पास किया जाता है । परिणाम (ओकटास), सामान्य रूप से, में लौटा हैEAX
।
जैसा कि पहले ही ऊपर कहा गया है, इनपुट को बिटमैप के रूप में लिया जाता है। विशेष रूप से, एक 32-bpp प्रारूप का उपयोग किया जाता है, थोड़ा-एंडियन प्रारूप में, लेकिन अल्फा चैनल (उच्चतम-क्रम बाइट) को अनदेखा किया जाता है। यह बहुत सी चीजों को सरल बनाता है, जिससे हम प्रत्येक पिक्सेल के माध्यम से पुनरावृति कर सकते हैं और इसके 32-बिट आरजीबी रंग मान की जांच कर सकते हैं। एक चतुर अनुकूलन भी यहाँ उपयोग किया जाता है। प्रत्येक रंग घटक को अलग करने और जाँचने के बजाय कि यह> = 192 है, हम केवल 0xC0C0C0 द्वारा पूरे 32-बिट मान को मुखौटा करते हैं और परीक्षण करते हैं कि क्या परिणाम है = = 0xC0C0C0। यह सभी "क्लाउड" रंगों के लिए सही और सभी "आकाश" (गैर-क्लाउड) रंगों के लिए गलत का मूल्यांकन करेगा। कुंआ, मैं सोचा कि यह चतुर था! :-) यह निश्चित रूप से बड़ी संख्या में बाइट बचाता है।
इसलिए, इस कोड का परीक्षण करने के लिए, आपको इनपुट छवियों को 32-bpp बिटमैप पर कनवर्ट करना होगा। आप इसके लिए विंडोज पेंट का उपयोग नहीं कर सकते, क्योंकि यह अधिकतम 24 बिट्स-प्रति-पिक्सेल का समर्थन करता है। हालांकि, कई अन्य सॉफ़्टवेयर समाधान हैं जो इसे कर सकते हैं, जैसे कि एडोब फोटोशॉप। मैंने इस मुफ्त टूल का उपयोग किया , जो विंडोज पर एक पीएनजी को 32-बीपीपी बीएमपी में परिवर्तित करता है, जिसका अर्थ है कि आपको केवल जेपीईजी से पीएनजी (जो पेंट कर सकते हैं) में कनवर्ट करने की आवश्यकता है।
अन्य धारणाएं जो मैं प्रस्तुत करता हूं, वे उचित हैं:
- माना जाता है कि बिटमैप का आकार 0 से अधिक है ( यानी , इसमें कम से कम एक पिक्सेल शामिल है)। यह उचित है क्योंकि, जब वे आकाश शून्य होते हैं, तो हमें मौसम विज्ञान से बड़ी समस्याएं होती हैं।
- दिशा ध्वज (
DF
) को स्पष्ट माना जाता है ताकि हम बिटमैप के माध्यम से सही ढंग से पुनरावृति करेंगेLODSD
निर्देश । यह ज्यादातर x86 कॉलिंग कन्वेंशनों द्वारा बनाई गई एक ही धारणा है, इसलिए यह उचित लगता है। यदि आपको यह पसंद नहीं है, तो एक के लिए गिनती में 1 बाइट जोड़ेंCLD
निर्देश के ।
- X87 FPU के लिए राउंडिंग मोड को राउंड-टू-पास-सम-सेट पर सेट किया गया है। यह सुनिश्चित करता है कि जब हम परीक्षण के मामले # 4 द्वारा सत्यापित किए गए अस्थायी अस्थायी बिंदु से अंतिम पूर्णांक परिणाम तक ओकटास की संख्या में परिवर्तित करते हैं, तो हमें सही व्यवहार मिलता है। यह धारणा उचित है क्योंकि यह एफपीयू के लिए डिफ़ॉल्ट स्थिति है और इसे सी कोड में भी बनाए रखना आवश्यक है (जहां ट्रंकेशन डिफ़ॉल्ट राउंडिंग व्यवहार है, मजबूर करने वाले कंपाइलर जो निष्क्रिय कोड उत्पन्न करने के लिए मानक-अनुरूप होना चाहते हैं जो राउंडिंग को बदल देता है मोड, रूपांतरण करता है, और फिर गोलाई मोड को वापस बदलता है)।
असेंबली असेंबली mnemonics:
; int ComputeOktas(void* bmpBits /* ESI */,
; uint32_t bmpSize /* ECX */);
push ecx ; save size on stack
xor edx, edx ; EDX = 0 (cloudy pixel counter)
CheckPixels:
lodsd ; EAX = DS:[ESI]; ESI += 4
not eax
and eax, 0x00C0C0C0
jnz NotCloudy
inc edx
NotCloudy:
loop CheckPixels ; ECX -= 1; loop if ECX > 0
shl edx, 3 ; counter *= 8
fild DWORD PTR [esp] ; load original size from stack
push edx
fild DWORD PTR [esp] ; load counter from stack
fdivrp st(1), st(0) ; ST(0) = counter*8 / size
fistp DWORD PTR [esp] ; convert to integer, rounding to nearest even
pop eax ; load result
pop edx
ret
निश्चित रूप से आपने इसे इस तरह से नीचे नहीं बनाया है और अभी भी सोच रहे हैं कि कोड कैसे काम करता है? :-)
खैर, यह बहुत आसान है। हम एक समय में बिटमैप एक 32-बिट मान के माध्यम से पुनरावृत्ति करते हैं, यह देखने के लिए कि क्या पिक्सेल आरजीबी मूल्य "बादल" या "बादल नहीं" है। यदि यह बादल है, तो हम अपने पूर्व-शून्य काउंटर को बढ़ाते हैं। अंत में, हम गणना: बादल छाए रहेंगे पिक्सल / कुल पिक्सेल × 8
(जो के बराबर है: बादल छाए रहेंगे पिक्सल / कुल पिक्सेल ÷ 0.125)।
इनपुट छवियों की आवश्यकता के कारण मैं इसके लिए TIO लिंक शामिल नहीं कर सकता। हालाँकि, मैं आपको उस वीणा के साथ प्रदान कर सकता हूँ जिसका मैंने विंडोज पर परीक्षण किया था:
#include <stdio.h>
#include <assert.h>
#include <Windows.h>
int main()
{
// Load bitmap as a DIB section under Windows, ensuring device-neutrality
// and providing us direct access to its bits.
HBITMAP hBitmap = (HBITMAP)LoadImage(NULL,
TEXT("C:\\...\\test1.bmp"),
IMAGE_BITMAP,
0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
assert(hBitmap != NULL);
// Get the bitmap's bits and attributes.
DIBSECTION dib;
GetObject(hBitmap, sizeof(dib), &dib);
assert(dib.dsBm.bmBitsPixel == 32);
uint32_t cx = dib.dsBm.bmWidth;
uint32_t cy = abs(dib.dsBm.bmHeight);
uint32_t sz = cx * cy;
assert(sz > 0);
int oktas = ComputeOktas(sz, dib.dsBm.bmBits);
printf("%d\n", oktas);
return 0;
}
हालांकि, इसके साथ सावधान रहें! जैसा कि ऊपर परिभाषित किया गया है, ComputeOktas
एक कस्टम कॉलिंग कन्वेंशन का उपयोग करता है, जो एक सी कंपाइलर का सम्मान नहीं करेगा। आपको अपेक्षित रजिस्टरों में स्टैक से मानों को लोड करने के लिए असेंबली भाषा प्रक्रिया के शीर्ष पर कोड जोड़ने की आवश्यकता है, जैसे :
mov ecx, DWORD PTR [bmpSize]
mov esi, DWORD PTR [bmpBits]