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
রেজিস্টারে । ফলাফল (Oktas), যথারীতি, ফিরে আসে EAX
।
ইতিমধ্যে উপরে বর্ণিত হিসাবে, ইনপুটটি বিটম্যাপ হিসাবে নেওয়া হয়। বিশেষত, 32-বিপিপি ফর্ম্যাটটি সামান্য-এন্ডিয়ান ফর্ম্যাটে ব্যবহৃত হয় তবে আলফা চ্যানেল (সর্বোচ্চ অর্ডার বাইট) উপেক্ষা করা হয়। এটি অনেকগুলি জিনিসকে সহজতর করে, আমাদের কেবল প্রতিটি পিক্সেলের মাধ্যমে পুনরাবৃত্তি করতে এবং এর 32-বিট আরজিবি রঙের মানটি পরীক্ষা করতে দেয়। একটি চতুর অপ্টিমাইজেশন এখানেও ব্যবহৃত হয়। প্রতিটি রঙের উপাদান বিচ্ছিন্ন করে>> = 192 হয় কিনা তা যাচাই করার পরিবর্তে আমরা কেবল 0xC0C0C0 দ্বারা পুরো 32-বিট মানটি মাস্ক করে ফলাফলটি> = 0xC0C0C0 হয় কিনা তা পরীক্ষা করি। এটি সমস্ত "ক্লাউড" রঙের জন্য সত্য এবং সমস্ত "আকাশ" (নন-ক্লাউড) রঙের ক্ষেত্রে মূল্যায়ন করবে। ভাল, আমি ভেবেছিলাম চালাক! :-) এটি অবশ্যই বিপুল সংখ্যক বাইট সংরক্ষণ করে।
অতএব, এই কোডটি পরীক্ষা করার জন্য, আপনাকে ইনপুট চিত্রগুলি 32-বিপিপি বিটম্যাপে রূপান্তর করতে হবে। আপনি এটির জন্য উইন্ডোজ পেইন্ট ব্যবহার করতে পারবেন না, কারণ এটি প্রতি পিক্সেল সর্বোচ্চ 24 বিট সমর্থন করে। যাইহোক, এমন অনেকগুলি সফ্টওয়্যার সমাধান রয়েছে যা এটি করতে পারে যেমন অ্যাডোব ফটোশপ। আমি ব্যবহার করতাম এই নিখরচায় সরঞ্জামটি , যা একটি পিএনজিকে উইন্ডোজে একটি 32-বিপিপি বিএমপিতে রূপান্তর করে, এর অর্থ আপনার কেবল জেপিইজি থেকে পিএনজি রূপান্তর করতে হবে (যা পেইন্ট করতে পারে)।
অন্যান্য অনুমান যে আমি পোস্ট করি তা বিশিষ্ট যুক্তিসঙ্গত:
- বিটম্যাপটি 0 (এর চেয়ে বড় আকারের) বলে ধরে নেওয়া হচ্ছে অর্থাত্) এটি কমপক্ষে একটি পিক্সেল ধারণ করে) বলে মনে করা হয়। এটি যুক্তিসঙ্গত কারণ কারণ যখন তাদের আকাশ শূন্য হয় তখন আমাদের আবহাওয়াবিদ্যার চেয়ে বড় সমস্যা হয়।
- দিকের পতাকাটি (
DF
) পরিষ্কার বলে ধরে নেওয়া হয়েছে যাতে আমরা ব্যবহার করে বিটম্যাপের মাধ্যমে সঠিকভাবে পুনরাবৃত্তি করবLODSD
নির্দেশটি । এটি বেশিরভাগ x86 কলিং কনভেনশনের দ্বারা করা একই ধারণা, তাই এটিকে ন্যায্য বলে মনে হচ্ছে। আপনি যদি এটি পছন্দ না করেন তবে একটি হিসাবে গণিতে 1 বাইট যুক্ত করুনCLD
নির্দেশের ।
- X87 এফপিইউর জন্য রাউন্ডিং মোডটি রাউন্ড-টু-নিকটতম-এমনকি-তে সেট করা হবে বলে ধারণা করা হচ্ছে। এটি নিশ্চিত করে যে পরীক্ষার কেস # 4 দ্বারা যাচাই করা আমরা ভাসমান-পয়েন্ট থেকে অস্থায়ী থেকে চূড়ান্ত পূর্ণসংখ্যার ফলাফলে রূপান্তর করি যখন আমরা সঠিক আচরণটি পাই। এই অনুমানটি যুক্তিসঙ্গত কারণ এটি এফপিইউর জন্য পূর্বনির্ধারিত রাষ্ট্র এবং এটি সি কোডের মধ্যেও বজায় রাখা প্রয়োজন (যেখানে কাটাটি ডিফল্ট রাউন্ডিং আচরণ হয়, অক্ষম কোড উত্পন্ন করতে মানদণ্ডের সাথে সম্মত হতে ইচ্ছুক সংকলককে বাধ্য করে যে রাউন্ডিং পরিবর্তন করে মোড, রূপান্তরটি করে, এবং তারপরে রাউন্ডিং মোড পরিবর্তন করে)।
অবহেলিত সমাবেশ মেমোনমিক্স:
; 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)।
ইনপুট চিত্রের প্রয়োজনীয়তার কারণে আমি এর জন্য টিআইও লিঙ্কটি অন্তর্ভুক্ত করতে পারি না। আমি যাইহোক, উইন্ডোজটিতে এটি পরীক্ষা করার জন্য আমি যে জোতা ব্যবহার করেছি তা আপনাকে সরবরাহ করতে পারি:
#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]