Khaled Alshaya

=||= مقدمة حول معاملات الـ Bit لجميع المبرمجين 2 =||=

7 ردود في هذا الموضوع

post-89451-1198550773_thumb.gif

السلام عليكم ,,

هذه هي الحلقة الثانية من سلسة دروس تطبيقية على مستوى الـ Bit. المقالة تتحدث بشكل رئيسي عن مجموعة من الخدع التي يمكن تنفيذها بمعاملات الـ Bit للحصول على أقصى سرعة ممكنة في بعض التطبيقات. سأحاول عرض الطريقة التقليدية بجانب الأمثلة حول استخدام المعاملات لتطبيق نفس المهام.قد تبدو بعض هذه التطبيقات الصغيرة بسيطة لأول وهلة, و لكنها تحتاج إلى اعتياد المبرمج على استخدامها في الوقت و المكان المناسبين, لأن هناك الكثير من المشاكل التي قد تظهر و هذه المشاكل من الصعب حلها بسهولة غالباُ. أود أن أذكر نقطة أعتقد أنها مهمة قبل الدخول إلى الأمثلة. إننا كمبرمجي لغات عالية المستوى لا نشغل فكرنا بالكثير من الأمور التي تخفيها اللغات عالية المستوى, إحدى هذه المشاكل هي طريقة تمثيل الأعداد في الذاكرة أو ما يسمى بالـ Endianness, و أيضاُ الفرق بين الأعداد ذات الإشارة و الأعداد الموجبة فقط أوما يسمى signed و unsigned, إذا كان لديك الهمة الكافية فالاطلاع على مثل هذه المواضيع سيثري فكرك البرمجي بشكل كبير, خصوصاُ عند الدخول في مواضيع مثل كيفية تمثيل الأعداد السالبة في المعالج و, للاستزادة اقرأ عن موضوع الـ Two's Complement كل ما تم الكلام عنه في الأعلى, يتحدث عن الأعداد الصحيحة فقط, و لا دخل لنا هنا بالأعداد الكسرية أو الـ Floating Point Numbers لأن موضوعها مختلف جداُ عن الأعداد الصحيحة.

من هذه النقطة تعاملنا سيكون مع النوع unsigned

unsigned int
unsigned char
unsigned short int

و عند ذكر أي نوع من الأنواع التي في الأعلى فسيعني ذلك أنه unsigned حتى و لو لم يتم ذكر unsigned في السياق.

post-89451-1198550777_thumb.gif

أكبر قيمة يمكن لمتغير أن يحملها - تجنب الـOverflow - :

يحتار المبرمجون أحياناُ في عمليات التحقق من قيمة مدخلة من مستخدم و بالذات القيم العددية. فلو طلبنا من المستخدم إدخال رقم صحيح int و أردنا أن نكتب أكبر قيمة يمكن لهذا النوع من المتغيرات أن تحملها, فكيف سنقوم بالعملية ؟

مثل هذا النوع من المشاكل قد لا يمكن حله من المحاولة الأولى بكل بساطة, لربما ستعتمد على مكتبات خارجية و بالتالي يصبح برنامجك أكبر من اللازم, أو تقوم بتسجيل أكبر قيمة لكل نوع في ثابت constant, و لكن هذه الطريقة بشعة جداُ لتنفيذ مثل هذا الأمر, و السبب أن حجم المتغير يختفق من معالج إلى آخر و من بنية إلى أخرى, المفروض أن مبرمجي ++C هم الأفضل :), انظر إلى المثال التالي الذي سوف يطبع لنا مجال متغير من نوع int.

unsigned int Number = 0;
cout << "The Domain of Integers in C++ : " << "[ " << Number << ", " << ~Number << " ]";

العملية التي قمنا بها كانت بسيطة جداُ,

قمنا بحجز متغير من نوع int و أسميناه Number و قيمته تساوي الصفر,

الجملة الثانية كانت للطباعة على الشاشة, و أكثر ما يثير انتباهنا هنا هي العبارة التالية :

~Number

قمنا بأخذ متمم الصفر, أي أن ما حدث هو كالتالي لو كنت تذكر المتمم من الدرس السابق :

00000000000000000000000000000000 // 32 bits = the size of int
~
=
11111111111111111111111111111111 // Every zero is now a one!

لو أردنا حساب المتمم في أي نظام أعداد, و في حالتنا هذه النظام الثنائي و بكل تأكيد المتمم يعتمد على عدد الخانات كما في مثال الـ int التي تمثل بـ 32 bits .

طريقة حساب المتمم تتم على الشكل التالي لعدد يسمى x على سبيل المثال :

unsigned int x
~x = ( (base)^NumberOfPlaces - x ) - 1

unsigned int x = 0
~x = ( (2)^32 - 0 ) - 1 = 4294967295

لاحظ أن 32 Bits تمكننا من تمثيل 4294967296 عدد بداية من 0 و حتى 4294967295

بعبارة أخرى المتمم هو العدد الذي لو جمع مع العدد المدخل لأعطانا أكبر رقم يمكن تمثيله, و ذلك يعتمد بالطبع على عدد الخانات.

post-89451-1198550768_thumb.gif

التحقق إذا كان عدد ما يقبل القسمة على 2 :

التطبيق الثاني قد يكون ذا شهرة أكبر من التطبيق الأول, سنحاول في السطور القادمة اكتشاف طريقة لفحص العدد إذا كان من مضاعفات العدد 2 أم لا, بمعنى آخر هل العدد المدخل يقبل القسمة على اثنين أم لا.

الطريقة التقليدية, و التي نقوم فيها باستخدام معامل باقي القسمة للتحقق إذا كان باقي قسمة العدد المدخل على 2 تساوي الصفر أو الواحد,

فلو كان العدد المدخل فردياُ لكان باقي القسمة 1, أما إذا كان زوجياُ فباقي القسمة يساوي 0.

unsigned int input = 0;
cout << "Enter a number : ";
cin >> input;
cout << endl;

if ( input % 2 == 0 )
cout << "Even Number";
else
if ( input % 2 == 1 )
cout << "Odd Number";

لا اعتراض على استخدام هذه الطريقة طبعاُ, و لكن دعني أذكرك أن الكود في الأعلى يستهلك جهد المعالج, لأن عمليات الضرب و القسمة و باقي القسمة, لا تنفذ بالسرعة التي تنفذ بها عمليات الجمع و الطرح, و لا تستغرب إن قلت لك أن عملية قسمة أو باقي قسمة واحدة تكلف عشرات أضعاف الوقت الذي تكلفه عملية جمع أو طرح, و من الممكن التخلص من العملية الحسابية المكلفة فيه عند الحاجة باستعمال المعامل & و هو عبارة عن عملية بسيطة يفهمها المعالج مباشرة للحصول على نفس النتيجة, انظر إلى الأعداد الثنائية التالية و التي كل منها يمثل Byte واحد :

00000001 = 1
00100000 = 32
00100011 = 35
11111110 = 254

لاحظ أن الـ Bit الأول في الأعداد الفردية دائماُ ما يكون 1, بينما في الأعداد الزوجية فهو دائماُ 0, و السبب أن الـ Bit الأول يمثل العدد 1, و الـ Bit الثاني يمثل 2, و الثالث 4, و كل Bit بعد ذلك يمثل قوى العدد اثنين و المهم هنا هو الـ Bit الأول, و بالتالي إذا عرفنا قيمة الـ Bit الأول لأمكننا الإجابة على السؤال المطروح : هل العدد فردي أو زوجي ?

المثال التالي يوضح الطريقة :

unsigned int input = 0;
cout << "Enter a number : ";
cin >> input;
cout << endl;

if ( input & 1 == 0 )
cout << "Even Number";
else
if ( input & 1 == 1 )
cout << "Odd Number";

تخيل أن المستخدم أدخل العدد 3 :

00000011
&
00000001
=
00000001 = 1 // Means the Number is odd.

و لو أن المستخدم أدخل عدد زوجي مثلاُ 8 :

00001000
&
00000001
-------------
00000000 = 0 // Means the Number is even.

هذه الطريقة قد نستخدمها في حلقة تتكرر آلاف المرات مثلاً و هذا شائع بالمناسبة في كثير من التطبيقات كعمليات الرسم و غيرها, و حينها سنلاحظ الفرق بين الطريقتين.

post-89451-1198550768_thumb.gif

التحقق إذا كان عدد ما من قوى العدد 2 :

كما تحققنا في الأعلى إذا كان عدد ما من مضاعفات العدد 2, توجد طريقة للتأكد إذا كان العدد من قوى العدد 2.

و لكن هل يمكنك التفكير بطريقة للتحقق ؟ غالباً ستستخدم عمليات القسمة مرات عديدة في حلقة, بكل تأكيد أداء برنامجك سيكون في الحضيض كما ذكرنا سابقاً.

الطريقة التالية سهلة و سريعة إلى أبعد الحدود :)

إن أي عدد من قوى العدد 2 في النظام الثنائي يمكن أن يشبه التالي :

00000010 = 2
00000100 = 4
00001000 = 8
00010000 = 16
00100000 = 32
.
.
.

و هكذا, نلاحظ وجود العدد الثنائي 1 مرة واحدة و الباقي أصفار, و لكن كيف يمكننا معرفة أن هناك "1" واحد فقط في العدد المراد فحصه ؟

لنأخذ العدد 16 على سبيل المثال, إذا قمنا بطرح 1 من العدد فسيصبح الناتج 15 :

00010000 = 16
-
00000001 = 1
=
00001111 = 15

لاحظ تكون سلسلة من الـعدد الثنائي 1 تبدأ مباشرة بعد الـ 1 في العدد الأصلي الذي أردنا أن نفحصه,

الآن لنقم بتطبيق عملية & على العدد الناتج و العدد الأصلي :

00010000
&
00001111
=
00000000

سينتج العدد صفر دائماً إذا كان العدد الذي أردنا فحصه من قوى العدد 2 كما اتضح سابقاً :), بينما لو جربنا العدد 17 مثلاً سينتج لنا عدد غير الصفر, و الناتج سيكون دائماً غير الصفر إذا كان العدد الأصلي ليس من قوى العدد 2 :

00010001 = 17
-
00000001 = 1
=
00010000 = 16

و نقوم بتطبيق عملية & مثل ما عملنا سابقاً :

00010001
&
00010000
=
00010000

فسنحصل على 16, بالتالي نعرف أن العدد الأصلي ليس من قوى العدد 2.

لنقم بكتابة دالة تقوم باستقبال عدد int و تقوم بإرجاع true إذا كان العدد من قوى العدد 2, أو false إذا كان غير ذلك :

bool IsPowOfTwo( unsigned int x ){
return !(x & (x-1));
}

كل ما أضفناه هو معامل النفي المنطقي الذي تكلمنا عنه في الدرس الأول, حيث سنقوم بتطبيق عملية التحقق, فإن كان العدد من قوى العدد 2 سنحصل على صفر - false - ثم سنقوم بنفيها فتصبح true لأن دالتنا ترجع true إذا كان العدد من قوى العدد 2 :), أما إذا كان ناتج عملية التحقق true فسنقوم بنفيها لكي ترجع دالتنا false.

post-89451-1198550768_thumb.gif

تبديل قيمة متغيرين :

عملية تبديل قيمة متغيرين تعتبر من أشهر المشاكل التي تواجه المبرمجين, أحد الحلول المقترحة هي استخدام متغير ثالث مؤقت خلال عملية التبديل :

void Swap( unsigned int &x, unsigned int &y ){
unsigned int z = x;
x = y;
y = z;
return;
}

و هذه العملية جيدة إلا أن عيبها أنها تستعمل متغير ثالث, قد تقوم ما المشكلة و ذواكر الحاسبات الشخصية وصلت إلى 4 GB و أكثر !!

المشكلة أن كثير من الـ Embeded Systems لا تملك الذواكر التي نتكلم عنها, و لا ننسى أن حجم هذه المتغيرات قد يكون كبيراً أو صغيراً و قد يؤثر إن كنا نريد تبديل عدد كبير من المتغيرات.

الطريقة الثانية و التي تصلح فقط للأعداد الصحيحة :

void Swap( unsigned int &x, unsigned int &y ){
x += y;
y = x - y;
x -= y;
return;
}

هذه الطريقة قد تبدو صحيحة للوهلة الأولى و لكنها تحتوي على خطأ فادح و هو إمكانية حصول Overflow, إذا كان العددان كبيران كفايةً, فلو أن x تساوي 4294967295 و كانت y تساوي 1, فـ x لن تستطيع حمل نتيجة الجمع مع y لأن أكبر قيمة يمكن لـ 32Bit تمثيلها هي 4294967295.

سنتعرف في السطور اللاحقة على المعامل ^ أو ما يسمى XOR, و الذي سيمكننا من إجراء عملية التبديل بدون الحاجة لمتغير ثالث أو حتى الخوف من حصول Overflow !!

يمكنك مراجعة عمل هذا المعامل من الدرس الأول, قبل الدخول في المثال التالي.

تصور أن لدينا عددين ثنائيين a تساوي 1 و b تساوي 0 :

a = 1
b = 0

لو قمنا بتطبيق عملية ^ على المتغيرين :

a = a ^ b // 1 ^ 0 = 1
// a = 1

ثم :

b = a ^ b // 1 ^ 0 = 1
// b = 1

ثم :

a = a ^ b // 1 ^ 1 = 0
// a = 0

لاحظ أننا قمنا بتبديل قيمة المتغيرين مع بعضهما البعض, و يمكنك تخيل العملية كالتالي - الخطوة الثانية في الأعلى - :

// b = a ^ b
b = (a^b) ^ b
b = a ^ (b^b) // b ^ b = 0 ^ 0 = 0
b = a ^ 0 // a ^ 0 = 1 ^ 0 = 1
// b now is 1 which was originally a.

و الآن مع الخطوة الثالثة :

// a = a ^ b
a = (a^b) ^ ((a^b) ^ b)
a = (a^b) ^ (a^b) ^ b
a = 0 ^ b
a = b

حاول التدقيق في الطريقة التي في الأعلى, فكل ما قمت به هو عملية التعويض عن a بالقيمة التي أسندناها له في أول خطوة حيث a = a^b و بعد ذلك أكمل الطريقة,

إضافة إلى أنك يجب أن تنتبه إلى أن :

a ^ 0 = a
a ^ a = 0

حاول استبدال a بأي عدد ثم طبق العمليتين اللتين في الأعلى لتفهم الموضوع كله. لن أفصل أكثر في الموضوع, و سأترك لك المجال للبحث حول خصائص المعامل XOR.

الآن لنقم بكتابة دالة بسيطة تقوم بعملية التبديل بين متغيرين int :

void Swap( unsigned int &x, unsigned int &y ){
x = x ^ y;
y = x ^ y;
x = x ^ y;
return;
}

إلى هنا نكون قد انتهينا من عملية التبديل بين متغيرين تاركين المجال للتطبيق الأخير.

post-89451-1198550777_thumb.gif

مصفوفة الـ Bool :

قد لاتكون التطبيقات السابقة ذات استعمالات عامة كالتطبيق الحالي, و السبب يرجع إلى أنها طرق لحل وظائف معينة فقط. سنتكلم في السطور القادمة حول مصفوفةالـ Bool Array. هذه المصفوفة عبارة عن مصفوفة عادية تحوي عناصر, كل عنصر يستطيع حمل إحدى قيمتين true أو false. كنت أريد وضع هذا التطبيق كأول تطبيق في هذه الحلقة و لكني قررت وضعه في آخر الحلقة لكي نستطيع الكلام حوله بقليل من التفصيل لأهميته الكبيرة.

يمكنك تخيل مصفوفة من النوع bool على الشكل التالي - و لنفرض أن هذه المصفوفة تحتوي على ثمانية عناصر :

1 True
2 False
3 False
4 True
5 False
6 True
7 True
8 False

كما تعلم يمكننا إنشاء هذه النوع من المصفوفات في ++C بالطريقة التالية :

bool BoolArray[8] = { True, False, False, True, False, True, True, False };

طبعاً حجم النوع bool عبارة عن Byte واحد, بالتالي المصفوفة حجمها ثمانية Bytes.

لنأخذ فكرة عن استخدام هذا النوع من المصفوفات, تخيل أن لدينا مصفوفة كل عنصر فيها عبارة عن كائن, وهذا الكائن يأخذ حيزاً كبيراً في الذاكرة, و كنا نريد التعامل مع المصفوفة من حيث الحذف و الإضافة, فقمنا بحذف إحدى الكائنات الموجودة في المصفوفة, الآن قمنا بعملية بحث في المصفوفة, كيف يمكننا معرفة الكائنات المحذوفة و الكائنات التي لم تحذف ؟

يمكننا بكل بساطة و سلاسة استخدام مصفوفات الـ bool. حيث كل كائن يقابله في مصفوفة الـ bool إما true إذا كان محذوفاُ أو false إذا لم يكن قد حذف و كان الكائن موجوداً بالفعل.

كمثال آخر, تصور أن لدينا صورة و الصورة تحوي نقاطاً Pixels و لون كل نقطة إما أن يكون أبيض أو أسود, حينها يمكننا تمثيل اللون الأبيض بـtrue و الأسود بـfalse.

سنترك الآن المثال الأول و نبقى مع مثال الصورة ثنائية الألوان لنصل إلى مصفوفة الـ Bits التي هي في الحقيقة تطبيقنا الأخير. كما نعلم أن كل صورة لها طول و عرض و لو قلنا على سبيل المثال أن عرض الصورة 512 Pixels و طولها 512 Pixels أيضاً. بضرب الطول في العرض سنحصل على الدقة أو الـ Resolution و في حالتنا هذه ستكون الـ Resolution عبارة عن 262144 نقطة Pixels و كنا قد استخدمنا مصفوفة bool و كل نقطة تمثل بـ Byte واحد بالتالي حجم الصورة سيكون 256 كيلو Bytes.

ماذا لو قلت لك أنني يمكنني تخزين صورتك تلك في مساحة و قدرها 32 كيلو Bytes فقط !!! و لن يكون هناك اختلاف بين الصورتين إطلاقاً !!!

لو أننا استخدمنا Byte لتمثيل كل نقطة لكان حجم الصورة ثمانية أضعاف الحجم لو أننا استخدمنا الطريقة التي سنتكلم عنها في السطور القادمة...

بما أننا نعرف من الحلقة الأولى أن كل Bit يمكن أن يمثل قيمتين 1 - true - أو 0 - false-, يمكننا إذاً تخزين كل نقطة في الصورة على شكل Bit بدلاً من Byte واحد كامل.

لن أناقش هنا كيفية تصميم مصفوفة Bits كاملة الوظائف, لأنها تحتاج إلى الكثير من الجهد و الاختبار لجعلها تعمل بشكل يمكننا الاعتماد عليه, بدلاً من ذلك يمكننا مناقشة تصميم ثلاث دوال أساسية في التعامل مع هذه المصفوفات.

قبل أن نبدأ يجب أن نعرف أن اللغات العالية المستوى لا توفر طريقة مباشرة للوصول إلى Bit مباشرة في int أو غيره من أنواع المتغيرات على سبيل المثال. ولكن بدلاُ من ذلك سنتستخدم معاملات الـ Bit للحصول على أي Bit نريده.

لتبسيط المناقشة سنفترض أن لدينا متغير حجمه Byte واحد - char - :

unsigned char x = 60; // x = 00111100

الآن سنتعلم ثلاث عمليات أساسية :

العملية الأولى إسناد 1 لأي Bit نريده من الثمان Bits الموجودة و هذه العملية تسمى setting a bit.

العملية الثانية اسناد 0 لأي Bit نريده من الثمان Bits الموجودة و هذه العملية تسمى clearing a bit.

العملية الثالثة هي الحصول على قيمة Bit في هذا الـ Byte و هذه العملية تسمى getting a bit.

إسناد 1 لـ Bit في Byte :

void setBit( char &Byte, char Pos ){
Byte = Byte | ( 1 << Pos );
return;
}

تصور أننا نريد أن نقوم بإسناد 1 للـ Bit الثامن - تذكر أن موقع الـ Bit الثامن هو 7 لأن أول Bit يقع في الموقع رقم 0 و الـ Bit الأخير سيكون في الموقع رقم 7 - :

أولاً سيكون لدينا الرقم 1 :

1 = 00000001

ثم سنقوم بإزاحة الواحد لليسار إلى الخانة المطلوبة :

1 << Pos
1 << 7 // = 10000000

الآن سنستخدم المعامل | - :

Byte | 10000000

00111100
|
10000000
=
10111100

المعامل | سيقوم بإجبار الـBit الثامن ليصبح 1 حتى ولو كان 0 أصلاً. أما باقي الـ Bits فستبقى على حالها.

إسناد 0 لـ Bit في Byte :

void clrBit( char &Byte, char Pos ){
Byte = Byte & ~( 1 << Pos );
return;
}

كما في عملية إسناد 1, لنفرض أننا نريد إسناد 0 للـ Bit الثالث :

سنقوم بإزاحة الواحد لليسار إلى الخانة المطلوبة :

1 << 2 // = 00000100

و الآن نقوم بتطبيق المتمم ~ :

~00000100 = 11111011

بالتالي يصبح لدينا 0 في الموقع المطلوب.

ثم نقوم باستخدام المعامل & :

Byte & 11111011

00111100
&
11111011
=
00111000

المعامل & سيقوم بإجبار الـ Bit الثالث ليصبح 0 حتى ولو كان 1 أصلاً. أما باقي الـ Bits فستبقى على حالها.

العملية الثالثة و الأخيرة هي عملية الحصول على قيمة Bit :

قبل الشروع في فهم هذه العملية, يجب أن تتذكر أننا قلنا أنه لا يوجد نوع متغيرات في ++C يمكنه حمل قيمة Bit واحد, لذلك سيتم استخدام النوع bool لحل مشكلة إرجاع قيمة الـ Bit.

bool getBit( char Byte, char Pos ){
return ( Byte & ( 1 << Pos ) );
}

لنفرض أننا نريد الحصول على قيمة الـ Bit الثاني, سنقوم أولاً بإزاحة الواحد للخانة المطلوبة :

1 << 1 // = 00000010

ثم نقوم بتطبيق المعامل & :

00111100
&
00000010
=
00000000

بالتالي حصلنا على الصفر و هي قيمة الـ Bit الثاني, طبعاُ لا بد أن نتذكر من الدرس الأول أن أي متغير من النوع bool يكون false إذا كانت قمية الـ Byte تساوي الصفر, و يكون true إذا كانت قيمة الـ Byte غير الصفر.

post-89451-1198550768_thumb.gif

إلى هنا نكون قد انتهينا من تعلم العمليات الأساسية التي تتم على مصفوفات الـ Bits, و لكنني لم أذكر الكثير من العمليات المتقدمة التي يمكن إجراءها على هذه المصفوفات لكي لا يطول الكلام.

قد لا يبدو هذا النوع من المصفوفات مهماً للمبرمج المبتدئ, و لكنها بكل تأكيد إحدى الـ Data Structiures الأساسية. لربما كان تصميم فئة كمصفوفة Bits أمراً ليس بالسهل حقيقة, لذلك ستجد في مكتبة STL القياسية التي تأتي مع جميع المترجمات, فئة تسمى bitset , هذه الفئة لأهميتها الكبيرة قام مبرمجوا المكتبة بضمها لمكتبتهم, لذلك يمكنك الاطلاع عليها و استعمالها بدلاً من تصميم مصفوفة خاصة بك.

إضافة إلى ذلك ألقي نظرة على التالي :

vector<bool> BoolArray;

هذا الـVector يحمل عناصر من النوع bool, و لكنه في الحقيقة يقوم بتحويلها إلى مصفوفة Bits داخلياً لزيادة الكفائة و الأدء عند التعامل مع مصفوفات الـ Bool. و هكذا نلاحظ أن مصفوفات الـ Bits حولنا في كل مكان و لكننا لا نلاحظها لأن التعامل المباشر مع هذا النوع يحتاج إلى الكثير من الخبرة البرمجية التي لا تتوفر لدى كثير من المبرمجين المبتدئين.

الآن تصور أن لديك مجموعة من الـ Bytes التي تريد إرسالها لحاسب آخر, هل فكرت في طريقة للتحقق إذا كانت هذه البيانات قد وصلت بشكل صحيح أم لا ؟

الحقيقة أن أبسط أنواع عمليات التحقق من الأخطاء تسمى عمليات الـ Parity Checking و هي تعتمد على مصفوفات الـ Bits أيضاً, يمكنك إلقاء نظرة على هذا الموضوع أيضاً على الرغم من أن هذه العمليات تتم في الغالب على مستوى الـ Hardware و بشكل قليل على مستوى الـ Software, إلا أنها تعطيك فكرة عما يجري في حاسوبك عند استلام بيانات من مصدر آخر.

post-89451-1198550777_thumb.gif

إلى هنا و تنتهي حلقتنا الثانية بحمد الله, الحلقة القادمة سوف تكون الحلقة الأخيرة, و سنتكلم فيها عن مفهوم التشفير و أنواعه بشكل مبسط و كيف يمكننا استخدام معاملات الـ Bit لتشفير البيانات و خصوصاُ النصوص. الحلقة القادمة سوف نتكلم فيها عن المعامل XOR و نفصل قليلاً في خصائصه لنرى كيف يمكن استخدامه في عملية التشفير.

1

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ما شاء الله موضوع مميز واسلوب جميل في العرض بارك الله فيك وزادك علما.

الحقيقه معاملات البت مدهشه ولم اكن اتوقع اني استفيد منها بهذا الشكل .

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مقالة رائعه واسلوب اروع ..

كثر الله ن امثالك اخي خالد ووفقهم في دنياهم ..

استمر في مثل هذه الحلقات ليستفيد الجميع من اشياء كانت غافله عنهم ..

تحياتي العطرة ..

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

ما شاء الله و لا قوة إلا بالله

موضوعك والتنسيق والتخطيط له اصابني بالإحباط...هل يا ترى بكون قادرة انجز مثله او على الاقل احاكيه؟

ما على الله عزيز. مثالك شجعني اكون مهتمة اكثر بالتخطيط والتنسيق للمواضيع, هذا غير الفائدة العلمية البارزة بكل وضوح من خلال النص. الله يوفقك خالد

مع تمنياتي لكم بالتوفيق

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ,,

الشكر لجميع الأخوة على هذا القدر من التشجيع :) ,,

و إن شاء الله عما قريب سوف نبدأ في مشروع هذه الدروس و هو الحلقة الأخيرة من هذه السلسة,

لي عودة إن شاء الله حول موضوع المشروع بإذن الله,, انتظرونا :D لأني أفكر بتغيير فكرة المشروع الأصلية إلى فكرة جديدة,

تحياتي ,,

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

السلام عليكم ,,

إضافة للتطبيقات التي في الأعلى, يوجد في منتدانا العديد من المواضيع التي تتكلم عن الموضوع ,

موضوع الأخت رغد :

تعين الخيارات بواسطة تقنية Bitmask

أيضاُ من السلسة القيمة لمبرمج الـ ++C القدير هاني الأتاسي و آخرون - الأسئلة تحتاج إلى تركيز عميق لأنها تحديات بين مؤسسي القسم :D :

شغل مخك (2)

شغل مخك (3)

شغل مخك (6)

شغل مخك (7)

شغل مخك (8)

شغل مخك (9)

شغل مخك (11)

تحياتي ,,

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه

مشكور اخ خالد على الموضوع الجميل.

0

شارك هذا الرد


رابط المشاركة
شارك الرد من خلال المواقع ادناه
زوار
This topic is now closed to further replies.

  • يستعرض القسم حالياً   0 members

    لا يوجد أعضاء مسجلين يشاهدون هذه الصفحة .