السلام عليكم:
قبل البدء: من لديها | لديه الخبرة و الاساسيات حول الاعداد الثنائية والعمليات عليها يقوم بالإنتقال مباشرة إلى العنوان (مفهوم قناع الخانات الثنائية BITMASK) مباشرة.
كنت دايما مشغولة البال لما أشوف مثل السطر التالي و خصوصاً في برمجة النوافذ عند تعيين الخيارات لنافذة معينة تقريباً مثل السطر التالي:
dialog_box = RESIZEABLE | CLOSE | OK | CANCEL;
و اللي هو عبارة عن تعيين خيارات مناسبة لمربع حوار ما. هذه الخيارات هي أن تكون النافذة قابلة للتغير الحجم وتحتوي على زرارات الإغلاق و الموافقة و الإلغاء.
كنت حابة اتعرف على ما يجري خلف الكواليس و علاقة المؤثر (|) بهذه الثوابت وكيفية تعرف البرنامج على الخيارات المنتقاة بواسطتي. في النهاية طلع اسم هذه الطريقة قناع الخانات الثنائية BITMASK. (ماني عارفة لو ترجمتي صحيحة لكن هذي اقرب ترجمة للمصطلح هذا.)
الموضوع هو عبارة عن توضيح فكرة قناع الخانات الثنائية BITMASK و مدى ارتباطها بالمؤثرات الثنائية Bitwise Operators اللي هم (| وَ &) و نسميهم (أو , و) على التوالي. تحديداً, فإن المفهوم والفكرة اللي انا مجتهدة في توصليها لكم هي كيف يتم تعيين الخيارات و كيف يتعرف البرنامج على هذه الخيارات المنتقاة بواسطة BITMASK و المؤثرات (| وَ &).
لمحة سريعة على طبيعة الأعداد الثنائية:
النظام الثنائي هو النظام الذي له القاعدة 2. بعكس النظام العشري والذي قاعدته العدد 10. نحن نتعامل مع النظام العشري بشتى مجالات الحياة, لكن الكمبيوتر يتعامل بالنظام الثنائي. شوفوا طقم الأعداد التالي و الذي يتكون منه نظامنا العشري المعتاد:
0, 1, 2, 3, 4, 5, 6, 7, 8, 9
الآن نشوف طقم الأعداد اللي يتكون منها النظام الثنائي.
0, 1
لاحظوا أنه كل نظام و ليكن B يتكون من طقم الأعداد 0 إلى B-1. شوفوا طقم النظام العشري من صفر لحد عشرة ناقص واحد و اللي هو العدد 9. وكذلك تأملوا طقم النظام الثنائي و اللي هو من 0 لحد العدد 1. بالطبع, الكمبيوتر يتعامل مع العددين هذه بس ( 0, 1), ويمكننا بواسطة الأعداد الثنائية هذي تمثيل أي قيمة داخل الكمبيوتر و أيضاً تطبيق جميع العمليات الثنائية عليها, بالضبط مثل اللي رح نتعرف عليها قريباً و هي (| وَ &).
أوكي, نشوف الآن تمثيل للعدد 4 بواسطة النظام الثنائي داخل الكمبيوتر كالتالي: 100. و عشان تتأكدوا بأنها 4 حولوا هذا التمثيل من الثنائي إلى العشري بالطريقة التالية:
- نأخذ قيمة الخانة الموجودة بأقصى اليسار و نضربها في القاعدة 2 و نجمع الخانة التي تليها مع حاصل الضرب هذا.
- ثم نأخذ الناتج ونضربه في القاعدة 2 و نجمعه مع الخانة المباشرة التي لم نأخذها بعد.. و هكذا حتى نصل إلى آخر خانة موجودة بأقصى اليمين و نتوقف. بالضبط كما في المثال التالي:
100 = 1 * 2 + 0 -> 2 * 2 + 0 -> 4
هذه اسهل طريقة للتحويل من ثنائي إلى عشري وليست الطريقة الوحيدة, بأمكانكم مراجعة أي مصدر آخر بخصوص هذا الموضوع. انا مركزة في هذا الموضوع على التعامل مع الأعداد الثنائية والعمليات المنطقية عليها ومدى استخدامها في تعيين الخيارات. و لكن هذي لمحة سريعة فقط.
لمحة سريعة على عمل المؤثرات | وَ & على الأعداد الثنائية:
تحتوي لغة c++ على ستة مؤثرات تتعامل مباشرة و بتحيز مع البيانات الثنائية وهي كالتالي:
| & ^ ~ << >>
من مميزات هذه المؤثرات هي أنها تتعامل مع كل خانة من خانات العدد الثنائي بشكل منفرد. ما يهمنا في هذا الموضوع هما المؤثران | وَ &. و سنرى مثالين لكل واحد منهما في هذا الاقسم. بإمكانكم القيام بالبحث بخصوص العمليات الاربع الثنائية الأخرى من أي مصدر آخر.
اوكي, إن عمل المؤثر | و الذي يُدعى (أو Or) هو القيام بتعيين الحالة set state في الخانة الثنائية إلى واحد في حالة لو كان واحد على الأقل من الخانات له القيمة 1 (ركزوا على كلمة على الاقل), و غير ذلك فهو 0.
(طبعاً سنكتب التمثيل الثنائي للعدد مكون من 8 خانات Byte والتعويض بالصفر في خانات اقصى اليسار للعدد) مثل العدد 4 الذي تناولناه بالأعلى سيكون 00100 0000 مخزن في بايت داخل الكمبيوتر.
الآن نقوم بالتعامل مع العدد 4 0100 0000 و العدد 2 0010 0000 بواسطة المؤثر | لنتعرف على طريقة عمله بشكل عملي:
0000 0100 0000 0010 -------------- 0000 0110 Another example 0000 1000 0000 1000 -------------- 0000 1000
نلاحظ كما لو كنا نقوم بعملية جمع للخانات في النظام العشري المعتاد, بأن 0 | 0 = 0 , 1 | 1 = 1 , 1 | 0 = 1. لا يهمنا الترتيب هنا على الإطلاق حيث أن 1 | 0 = 1 و 0 | 1 = 1 لأن المؤثر | Or له الخاصية الإبدالية Commutative Property مثل الجمع العادي بالضبط. من المثال الأول قام المؤثر | بين العدد 4 و 2 بإنتاج القيمة 0110 0000 و هي 6. و المثال الذي يليه و هو العدد 8 مع العدد 8 باستخدام المؤثر | انتج العدد 8 1000 0000 ايضاً و ذلك بالتعامل مع الاعداد الثنائية خانة تلو الأخرى كما في تعريف المؤثرات الثنائية السابق و هي ميزة من مميزات هذه المؤثرات على الأعداد.
الآن نتناول المؤثر & و الذي يقوم بالمقارنة بين الخانات الثنائية فإذا كانت كلها 1 يعطي الناتج 1 و غير ذلك فالناتج 0. نأخذ نفس الامثلة السابقة للنتعرف على عمل المؤثر & and:
0000 0100 0000 0010 -------------- 0000 0000 Another example 0000 1000 0000 1000 -------------- 0000 1000
لاحظوا أن هذا المؤثر لا يعطي القيمة 1 إلى إذا و فقط إذا كانت جميع الخانات أو المدخلات لها القيمة 1.
مفهوم قناع الخانات الثنائية BITMASK:
قناع الخانات الثنائية عبارة عن طريقة لضغط المعلومات المتعلقة بخيارات و سمات (ميزات) نظام ما. و هذه الطريقة جيدة بالتحديد إذا كانت هذه الخيارات والسمات محدودة. هذه الخيارات (السمات) تكون مخزنة على شكل ثوابت عددية, و قيمة كل منها هو قيمة مختلفة لقوى العدد 2 يعني 2N. هذا يعني 1, 2, 4, 8, 16, 32… وهي قيم العدد 2 مرفوعة للقوى من 0 إلى ما شاء الله, و لكن لا تنسوا أن هذه الطريقة نافعة في حالة إذا كان هناك خيارات وسمات محدودة يتميز بها ذلك النظام.
أولا هناك ميزة تميز هذه الاعداد (نواتج قوى العدد 2 "2N") عن الاعداد المنتظمة المعروفة 1 2 3 4 5 6 ... بأنها حتماً تنتج قيمة فريدة عند جمعها مع بعض البعض. على سبيل المثال. لا حظوا في الاعداد المنتظمة لو جمعنا 1 + 2 + 4 = 7, و 2 + 5 ايضاً = 7. لكن لاحظوا أننا لو قمنا بهذه العملية بكل الاشكال مع اعداد قوى العدد 2 فإننا حتماً سنحصل على ناتج فريد عن النواتج الأخرى. المربع التالي يسرد نواتج قوى العدد 2 ( من 20 إلى 232):
1 2 4 8 16 32 64 128 256 512 1024 2048 4096 8192 16384 32768 65536 131072 262144 524288 1048576 2097152 4194304 8388608 16777216 33554432 67108864 134217728 268435456 536870912 1073741824 2147483648
والمصادفة الجميلة هنا أن المؤثر الثنائي | يقوم بهذه العملية مع هذه الاعداد (قوى 2) بالضبط مثل مؤثر الجمع المعروف (+) مع الاعداد العشرية. و يعطي نواتج فريدة عند تعامله مع هذه الاعداد (قوى 2) وكأنها يقوم بجمعها مثل عملية الجمع. اوكي, لنتأكد من المثال التالي:
2 | 4 = 6 بالضبط مثل 2 + 4 = 6. لاحظوا إن العددان 2 و 4 من الاعداد الناتجة عن قوى العدد 2.
والمصادفة الأجمل أن المؤثر & يقوم بتحدد عما لو كان العدد المقارن مع الناتج هو من ضمن مكوناته الحسابية أو لا مثلا: 4 & 6 = 4 و 2 & 6 = 2 لكن 1 & 6 = 0 و هذا يعني أن العدد 1 ليس من أحد المكونات التي نتج عنها العدد 6 بواسطة المؤثر |. حاولوا التجربة بواسطة تحويل الاعداد السابقة 2 و 4 و 6 إلى تمثيل ثنائي وشاهدوا العملية ثنائية عشان تحققوا نتيجة أكبر في الفهم. مثل 2 0010 و 4 0100 بواسطة المؤثر | ينتج 6 0110 كما في المثال التالي:
0010 0100 ------- 0110
انا معتمدة عليكم الآن تجربوا مؤثر & بين العدد 6 و 2 ثنائياً وتشوفوا الناتج على الورقة. و تحاولوا تتطبقوا المفهوم هذا على العدد 16 | 8 | 2 و من ثم احصلوا على الناتج و استخدموا المؤثر & مع أحد مكونات وشوفوا الناتج؟
اوكي إذا قناع الخانات الثنائية BITMASK في أمثلتنا هذي هو حزمة ثوابت أعداد القوى 2 مترابطة باستخدام المؤثر | مثل ( 2 | 4 | 16 | 64 | ).
تمثيل هذا المفهوم بواسطة لغة c++:
أنا أول ما اتعلمت هذه اللغة حبيت مفهوم العداد enumration كثير, ماكنت عارفة السبب. لكن الآن اكتشفت بأنه أداة سهلة جداً لجمع قيم ثابتة في حزمة معينة و إعطائها اسماء مناسبة تسهل عملية كتابة وفهم البرنامج. وطبعاً انا مستخدمته في المثال التالي لضم الثوابت والخيارات المتعلقة بالنظام.
الآن قمت بكتابة برنامج بسيط جداً. عبارة عن برنامج يقوم بطباعة خيارات الأخوات ( فاطمة, أمل, مرام, زهرة, وأنا) حول نكهات الآيس كريم المحببة لديهم من خيارات ثابتة ومحزومة داخل enum و مقيمة بواسطة قوى العدد 2. هذه الخيارات كالتالي:
VANILLA : فانيلا CHOCOLATE : شوكليت CARAMEL :كاراميل STRAWBERRY : فراولة NUTS : جوز(بندق) PISTACHIO : فستق ALL : جميع ما سبق
اللي انا ابغاكم تركزوا عليه هو إن القيم لهذه الثوابت هي قيم قوى العدد 2 من الأس 0 لحدة الأس 6 يعني القيم التالي على التوالي (1, 2, 4, 8, 16, 32): و تركزوا على كيفية طريقة تعيين الخيارات بواسطة هذه الثوابت مع المؤثر | كاقتراح عند نداء الإجراء setOptions لطلب و ذوق كل بنت مننا.
//The concept of the BITMASK.
/*
Authored by Raghad: to illustrate the Bitwize |, & (and,or)
operators and the BITMASK concept.
*/
#include <iostream>
using std::cout;
using std::endl;
//The IC-OPTIONS enum holds the Ic-cream Options.
enum IC_OPTIONS
{
VANILLA = 1,
CHOCOLATE = 2,
CARAMEL = 4,
STRAWBERRY = 8,
NUTS = 16,
PISTACHIO = 32,
ALL = 64
};
void setOptions(unsigned int);
int main()
{
cout << "Fatemah choice:" << endl;
setOptions(CARAMEL | PISTACHIO | VANILLA);
cout << "Amal choice:" << endl;
setOptions(ALL);
cout << "Maram choice:" << endl;
setOptions(STRAWBERRY|VANILLA);
cout << "Zahrh choice:" << endl;
setOptions(VANILLA | CHOCOLATE | CARAMEL | PISTACHIO);
cout << "Raghad choice:" << endl;
setOptions(PISTACHIO | NUTS | VANILLA);
return 0;
}
void setOptions(unsigned int bitmask)
{
cout << "Ic-cream with the following flavor(s):\n";
//Check if an individual option constructs the
//BITMASK or not using the bitwise and & operator.
if (bitmask & VANILLA)
cout << "- Vanilla" << endl;
if (bitmask & CHOCOLATE)
cout << "- Chocolate" << endl;
if (bitmask & CARAMEL)
cout << "- Caramel" << endl;
if (bitmask & STRAWBERRY)
cout << "- Strawberry" << endl;
if (bitmask & NUTS)
cout << "- Nuts" << endl;
if (bitmask & PISTACHIO)
cout << "- Pistachio" << endl;
if (bitmask & ALL)
cout << "- All of the flavors sorts" << endl;
cout << endl;
}بعدين لاحظوا داخل الإجراء setOption وكيفية التحقق من لو كان قيمة أحد الخيارات هذه من أحد مكونات الـ BITMASK الممرر إلى الإجراء أو لا. و هذا بواسطة المؤثر & .
انا قررت اقدم البرنامج بشكل مبسط عشان الفهم يكون اسهل. و ان شاء الله يكون الموضوع مفيد والله ولي التوفيق.



