عمليات بوليانية على الخانات وموازين
10.1 مقدمة – מבוא
كما تعلمنا يوجد نوع بيانات اسمه byte وهو أصغر من int حيث أنه يستطيع أن يحتوي رقماً صحيحاً بالمجال من 0 حتى 255 يشمل الصفر ويشمل العدد 255.
سنتعامل أحياناً في هذا الفصل مع byte وذلك لسهولة التعامل مع عدد قليل من الخانات حيث أن المتغير من نوع byte يتم تخزينه في الذاكرة في 8 خانات (8 bit) حيث يُعتبر ال byte وحدة ذاكرة صغيرة، بينما مُعطيات من نوع int فانه يتم تخزينها في الذاكرة في 32 خانة.
byte و intstatic void Main(string[] args)
{
int x = 98;
byte y = 98;
Console.WriteLine("x={0}", x);
Console.WriteLine("y={0}", y);
x++;
y++;
Console.WriteLine("*************");
Console.WriteLine("x={0}",x);
Console.WriteLine("y={0}",y);
}x=98 y=98 ************* x=99 y=99
كل خانة تستطيع أن تحتوي على 1 أو 0 بالذاكرة لان الأرقام تُخزن بالميزان الثنائي.
هذا الرقم يُخزن في int وهذه الخانات تكون LSB من بين ال 32 خانة (تُخزن من خانة 0 حتى خانة 8) والباقي يكون صفر (أصفار) أي من خانة 9 حتى خانة 31 يكون أصفار.
أي يكون الرقم يُحفظ بالذاكرة على الشكل التالي:
ومنا هنا أفضل لنا التعامل مع نوع بيانات byte إذا اردنا التعامل مع خانات الأرقام. ولكن حتى لو تعاملنا مع المُتغيرات int فاننا سنتعامل مع الخانات الأولى LSB وباقي الخانات التي ستخرج خارج مجال المكمل لل 2 (משלים ל-2) ستكون قيمتها غير صحيحة وذلك لأننا في int نتعامل مع أرقام لها إشارات.
طبعاً هذا الرقم (270) لا يمكن تخزينه بنوع بيانات byte لأنه أكبر من 255 وكما رأينا يحتاج الى 9 خانات لتخزينه (من خانة 0 حتى خانة 8).
- أكبر رقم في
byteهو: 11111111 وهو مساوٍ للرقم 255 بالعشري. - اكبر رقم في
intهو : 1111 .... 111 (31 خانة للرقم) وبقيت خانة للأشارة + أم – وهذا الرقم هو عبارة عن 2147483647 في الميزان العشري.
10.2 تعويض أرقام في موازين مختلفة للمتغيرات من داخل البرنامج – הצבת מספרים בבסיסים שונים
في لغة السي شارب نستطيع تعويض أرقاما للمتغيرات داخل البرنامج بواسطة العملية =
(1) تعويض رقم عشري (Dec):
اذا اردنا تعويض رقماً عشريا في المتغير نكتبه مباشرة. مثل:
(2) تعويض في الميزان 16 (HEX):
اذا اردنا تعويض رقماً في الميزان 16 (HEX) في المتغير نكتبه بحيث نكتب قبله 0x أو 0X (صفر وحرف x صغير أو كبير). مثل:
(3) تعويض في الميزان الثنائي (Bin):
اذا اردنا تعويض رقماً في الميزان الثنائي (Bin) في المتغير نكتبه بحيث نكتب قبله 0b أو 0B (صفر وحرف b صغير أو كبير). مثل:
المتغير num يمكنه أن يكون من نوع int أو byte.
10.3 طباعة قيمة متغيرات بموازين مختلفة على الشاشة – הדפסת ערכים בבסיסים שונים
يمكننا تخزين قيم مختلفة داخل المتغيرات وذلك حسب نوعها.
اذا أردنا طباعة قيمة متغير على الشاشة بميزان عشري (الوضع الطبيعي) نستعمل الأمر Console.Write ونستعمل الأداة {} كما يلي:
{0} او {0:d} أو {0:D} داخل الجملة النصية في الامر Console.Write
اذا أردنا طباعة قيمة متغير على الشاشة بميزان 16 (HEX) نستعمل الأمر Console.Write ونستعمل الأداة {} كما يلي:
{0:x} أو {0:X} داخل الجملة النصية في الامر Console.Write
10.4 العمليات على البيانات والمُعطيات – הפעולות על הנתונים
تعلمنا سابقا كل العمليات التالية:
| العملية | شرح |
|---|---|
+ | جمع |
- | طرح |
* | ضرب |
/ | قسمة |
% | الباقي من القسمة |
++ | إضافة 1 |
-- | تنقيص 1 |
+= | جمع الرقم مع القيمة السابقة |
-= | طرح الرقم من القيمة السابقة |
*= | ضرب الرقم مع القيمة السابقة |
/= | قسمة القيمة السابقة على الرقم |
%= | باقي قسمة القيمة السابقة على الرقم |
فئة Math | حسابات رياضية خاصة |
|| | علاقة أو منطقي في الشروط |
&& | علاقة وأيضا منطقي في الشروط |
== | مقارنة (مساواة) |
!= | مقارنة ( لا يساوي) |
< | مقارنة (تفاضل) |
> | مقارنة (تفاضل) |
<= | مقارنة (تفاضل أو مساواة) |
>= | مقارنة (تفاضل أو مساواه) |
كل هذه العمليات عملت على البيانات المُختلفة بالميزان العشري.
سنتعلم عمليات جديدة على خانات الرقم المُخزنة (خاناته التي تحتوي رقما بالميزان الثنائي 0 أو 1) :
| العملية | عملها | شرح |
|---|---|---|
& | bitwise And | عملية وأيضا And على كل خانة وخانة من خانات الرقم المُخزنة بالميزان الثنائي |
| | bitwise Or | عملية أو Or على كل خانة وخانة من خانات الرقم المُخزنة بالميزان الثنائي |
~ | bitwise Not | عملية نفي Not على كل خانة وخانة من خانات الرقم المُخزنة بالميزان الثنائي |
^ | bitwise XOR | عملية XOR على كل خانة وخانة من خانات الرقم المُخزنة بالميزان الثنائي |
<< | Shift Left | إزاحة خانات الرقم المُخزنة بخانة واحدة لليسار |
>> | Shift Right | إزاحة خانات الرقم المُخزنة بخانة واحدة لليمين |
| a | b | a | b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 1 |
| a | b | a&b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 0 |
| 1 | 0 | 0 |
| 1 | 1 | 1 |
| a | ~a |
|---|---|
| 0 | 1 |
| 1 | 0 |
| a | b | a^b |
|---|---|---|
| 0 | 0 | 0 |
| 0 | 1 | 1 |
| 1 | 0 | 1 |
| 1 | 1 | 0 |
ملاحظات:
- إجراء عملية أو لرقم مع 0 لا تؤثر. x | 0 = x
- إجراء عملية أو لرقم مع 1 تسبب أن تكون النتيجة بالضرورة 1. (تضع 1) x | 1 = 1
- إجراء عملية وأيضا لرقم مع 0 تسبب أن تكون النتيجة صفر بالضرورة. x & 0 = 0
- إجراء عملية وأيضا لرقم مع 1 لا تؤثر. x & 1 = x
- إجراء عملية Xor للرقم مع 1 يقلب الرقم (0➔1 و 1➔0)
تحريك خانة لليسار:
تحريك خانة لليمين:
- نتذكر أن تحريك الخانات لليسار في الميزان الثنائي يعني ضرب الرقم ب 2 أو مضاعفاته، وتحريك الرقم لليمين في الميزان الثنائي يعني قسمة الرقم على 2 أو مضاعفاته.
static void Main(string[] args)
{
int a = 7; // 7 = 00000111
int b = 2; // 2 = 00000010
int not_a , not_b,c,d,e;
not_a = ~a; //not_a=11111000 =>it`s negative so with 2`C it`s negative of 8
not_b = ~b; //not_b=11111101 =>it`s negative so with 2`C it`s negative of 3
c = a | b;
d = a & b;
e = a ^ b;
Console.WriteLine("Value of not_a is {0}", not_a);
Console.WriteLine("Value of not_b is {0}", not_b);
Console.WriteLine("Value of a|b is {0}", c);
Console.WriteLine("Value of a&b is {0}", d);
Console.WriteLine("Value of a^b is {0}", e);
Console.ReadKey();
}نتيجة تشغيل البرنامج:
Value of not_a is -8 Value of not_b is -3 Value of a|b is 7 Value of a&b is 2 Value of a^b is 5
الشرح:
بعد اجراء عملية Not خانة خانة هنا نرى ان الأرقام التي نحصل عليها سالبة (لان خانة الإشارة 1 (فعالة)) لذلك لكي نعرف ما هي هذه الأرقام السالبة نعمل لها مكمل لل 2 (2`C) وتظهر لنا القيمة الموجبة المضادة لهذه الأرقام السالبة وهكذا نعرف ما هي.
أمثلة على عمليات إزاحة خانات لليسار (<<) وازاحة لليمين (>>):
static void Main(string[] args)
{
int a = 11; // 11 = 00001011
int b = 60; // 60 = 00111100
int c,d;
c = a << 2; // 2 steps left
d = b >> 2; // 2 steps right
Console.WriteLine("c is {0}", c);
Console.WriteLine("d is {0}", d);
}نتيجة تشغيل البرنامج هي:
c is 44 d is 15
10.5 استعمال قناع (מיסוך – mask) – שימוש במסכה
الهدف من هذه العملية (تقنية) هو قراءة قيمة خانة مُعينة من كلمة. مثلا نريد أن نفحص ما هي قيمة الخانة السادسة بالرقم 241 (الذي هو 11110001) .
عملية التقنيع (وضع قناع) هي عملية فيها نستعمل عملية And مع قناع الذي يكون فيه خانات صفر في الأماكن التي لا نهتم بها (بالخانات التي لا تهمنا) بينما يكون قيمة الخانة التي تهمنا في القناع هي 1 .
في المثال القناع هو (00100000) جميع الخانات 0 (من الأولى حتى الخامسة والسابعة والثامنة) بينما الخانة السادسة التي نهتم بها بالرقم الأصلي (241) فإننا نضع بالقناع 1 .
هذا يضمن لنا ان كل خانات الرقم الأصلي ستلغى (تصبح صفر لان عمل وأيضا مع صفر سيسبب صفراً بالضرورة) وأما الخانة المرغوب بها فستبقى (لان عملية وأيضا مع الخانة المرغوبة هو بقاء قيمة الخانة المرغوبة على ما هي عليه حيث إن كانت صفراً ستبقى صفراً وإن كانت 1 ستبقى 1)
ثم بعد عملية وأيضاً مع القناع تبقى لنا خانة واحدة في المُعطى ولكن :
- إن أصبح المُعطى صفرا (حصلنا على صفر) معناها أن الخانة المرغوبة كانت صفر.
- إن لم نحصل على معطى صفر معناها أن الخانة المرغوبة ليست صفراً، انما 1.
static void Main(string[] args)
{
int num = 117; // 117 = 01110101
int mask = 0b00010000; // mask = 16;
int res;
res = num & mask;
if(res==0)
Console.WriteLine("Bit number 5 in number {0} is 0",num);
else
Console.WriteLine("Bit number 5 in number {0} is 1", num);
}نتيجة تشغيل البرنامج:
Bit number 5 in number 117 is 1
معرفة الرقم الذي نستقبله إذا كان زوجي أم لا بدون استعمال مودولو:
معلوم أن الرقم يكون زوجيا اذا كانت اقل خانة فيه LSB بالميزان الثنائي هي 0 بينما اذا كانت أقل خانة فيه LSB هي 1 فان الرقم فردي. لذلك تهمنا هذه الخانة.
اذا أجرينا قناع فيه 1 فقط في الخانة اليمنى LSB أي 00000001 فاننا سنحصل اما على صفر أو 1 بعد عملية التقنيع (And) حيث أنه من سيقرر ذلك هي الخانة الأولى بالرقم الأصلي التي نهتم بها (LSB) .
اذا كانت النتيجة:
- صفراً (0) فان الرقم الأصلي كان يحتوي على 0 في خانة LSB اذا هو زوجي.
- ليست صفراً (1) فان الرقم الأصلي كان يحتوي على 1 في خانة LSB اذا هو فردي.
%الحل:
static void Main(string[] args)
{
int num;
int mask = 0b00000001; // mask = 1;
int res;
Console.Write("Insert a number: ");
num = int.Parse(Console.ReadLine());
res = num & mask;
if(res==0)
Console.WriteLine("The number {0} is even",num);
else
Console.WriteLine("The number {0} is odd", num);
}نتائج تشغيل البرنامج:
Insert a number: 64 The number 64 is even
Insert a number: 37 The number 37 is odd