العمليات الحسابية في البرمجة

السلام عليكم ورحمة الله وبركاته

وقت القراءة: ≈ 25 دقيقة (بمعدل فنجان واحد من الشاي 😊)

المقدمة

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

وهنا أنواع متنوعة من العمليات التي يمكنك أن تقوم بها من ضمنها

العمليات الحسابية البسيطة

العمليات الحسابية التي كنت تقوم بها في الرياضيات ستجدها كما هي في لغات البرمجة البرمجة ولكن مع بعض الاختلافات والاضافات الطفيفة

معظم لغات اللبرمجة ستجدها تقدم لك العمليات الحسابية الأساسية مثل:

الجمع +

في أي لغة برمجة نستخدم + لكي تجمع مجموعة من الأرقام

int sum_1 = 5 + 3 + 10; // 18
float sum_2 = 5.5 + 3.5 + 10.5; // 19.5

الأمر بسيط كما ترى هنا جمعنا الأرقام 5 و 3 و 10 ثم خزنا الناتج وهو 18 في متغير sum_1 نوعه int
وفي السطر الثاني جمعنا الأرقام 5.5 و 3.5 و 10.5 وحصلنا على الناتج 19.5 وخزناه في متغير sum_2 نوعه float

لكن سؤال هنا هل يمكننا جمع قيم من نوعين مختلفين؟
الإجابة نعم في معظم اللغات لكن ستقابلك مشكلة أثناء التخزين

int sum = 5 + 3.5;

هنا قمنا بجمع العددين 5 و 3.5 ستجد أن الناتج هو 8.5
ولكن عند محاولة تخزينه في متغير من نوع int ستجد أن الجزء الكسري تم حذفه وتم تخزين القيمة 8 فقط وليس 8.5

التحويل الذي حصل يسمى casting وهي عملية تحويل القيم من نوع إلى نوع آخر
في المثال السابق تم تحويل القيمة 8.5 التي كانت من نوع float إلى 8 وأصبحت من نوع int


بعض اللغات تسمع لك بالقيام بعمليات الجمع بين المتغيرات النصية من نوع string
وهنا يتم دمج النصوص معًا وليس جمع الأرقام

string first_name = "Ahmed";
string last_name = "El-Tabarani";

string name = first_name + ' ' + last_name;

لدينا متغيرين من نوع string الأول first_name والثاني last_name
ثم قمنا بجمع المتغيرين مع مسافة بينهما وحصلنا على الناتج النهائي Ahmed El-Tabarani في المتغير name

الطرح -

في أي لغة برمجة نستخدم - لكي نقوم بعملية الطرح

int sub_1 = 10 - 5; // 5
float sub_2 = 10.2 - 5.5; // 4.7

هنا قمنا بطرح العددين 10 و 5 وحصلنا على الناتج 5 وخزناه في متغير sub_1
وفي السطر الثاني قمنا بطرح العددين 10.2 و 5.5 وحصلنا على الناتج 4.7 وخزناه في متغير sub_2

وتذكر أن هنا ستحدث نفس الشيء عند محاولة تخزين قيمة من نوع float كـ 4.7 في متغير من نوع int سيتم تخزين القيمة كـ 4 فقط

int sub = 10.2 - 5.5; // 4

الضرب *

في لغات البرمجة نستخدم * لكي نقوم بعملية الضرب

int mul_1 = 5 * 3; // 15
float mul_2 = 5.5 * 3.5; // 19.25

هنا قمنا بضرب العددين 5 و 3 وحصلنا على الناتج 15 وخزناه في متغير mul_1
وفي السطر الثاني قمنا بضرب العددين 5.5 و 3.5 وحصلنا على الناتج 19.25 وخزناه في متغير mul_2

في لغات حديثة تستخدم * و × للضرب ولكن في معظم اللغات ستجدها تستخدم * فقط


هناك لغات مثل الـ Python تسمح لك بالقيام بعمليات الضرب بين النصوص string لتكرار النص

name = "Ahmed" * 3 # AhmedAhmedAhmed

هنا قمنا بضرب النص Ahmed في العدد 3 وحصلنا على الناتج AhmedAhmedAhmed وهو تكرار النص ثلاث مرات
كل لغة قد تقدم لك بعض الخصائص والمميزات لتسهل عليك بعض الأمور لذا ادرس للغة التي تنوي تعلمها وتعرف مميزاتها

القسمة /

في لغات البرمجة نستخدم / لكي نقوم بعملية القسمة

int div_1 = 10 / 2; // 5
float div_2 = 10.5 / 2.5; // 4.2

هنا قمنا بقسمة العددين 10 على 2 وحصلنا على الناتج 5 وخزناه في متغير div_1
وفي السطر الثاني قمنا بقسمة العددين 10.5 على 2.5 وحصلنا على الناتج 4.2 وخزناه في متغير div_2

في لغات حديثة تستخدم / و ÷ للقسمة ولكن في معظم اللغات ستجدها تستخدم / فقط

هناك أمور في القسمة يجب أن تعرفها جيدًا

float div = 3 / 2;

هنا قمنا بقسمة العددين 3 على 2 الناتج البديهي هو 1.5 ولكن ستتفاجيء بأن الناتج الذي حصلنا عليه هو 1 فقط برغم من أن المتغير div من نوع float
هذا يحدث لأن القيمتين 3 و 2 هما من نوع int وعند قيام العملية الحسابية تم تحويل الناتج إلى int وليس float
لأن لغات البرمجة ستتعامل بالنوع فعندما تجد قيمتين من نوع int ستقوم بإعطاءك الناتج من نوع int

لكي تحصل على الناتج الصحيح يجب أن تقوم بتحويل أحد الرقمين إلى float

float div = 3.0 / 2; // 1.5

هنا قمنا بتحويل الرقم 3 إلى 3.0 هكذا ستفهم اللغة أن الرقم من نوع float وبالتالي سيتم تحويل الناتج إلى float وليس int
يكفي أن تقوم بتحويل أحد الأرقام إلى float لتكون الحسبة كلها من نوع float لأن الـ float يطغى على الـ int في الحسابات

هناك لغة مثل Python تستخدم / للقسمة ولكن تعطيك الناتج بنوع float مباشرة
وتستخدم // للقسمة ولكن تعطيك الناتج بنوع int

div = 3 / 2 # 1.5
div = 3 // 2 # 1

يوجد طرق أخرى لتحويل الأرقام من int إلى float وتسمي casting كما ذكرنا سابقًا وهي كالتالي:

يمكنك فعل الشيء لتحويل الأرقام من float إلى int بنفس الطرق

باقي القسمة %

في لغات البرمجة نستخدم % لكي نقوم بعملية القسمة ونحصل على الباقي
قد تسمى Modulus أو Remainder وهي باقي القسمة بين العددين

بعض اللغات قد تجدها تستخدم mod بدلاً من % لكي تقوم بعملية باقي القسمة

int mod = 3 % 2; // 1

على سبيل المثال 3 % 2 تعني باقي القسمة بين 3 و 2 هو 1
وهذا معناه أن ناتج القسمة 3 / 2 يعطينا عدد عشري وهو 1.5 بسبب أنه لا يمكن قسمة 3 / 2 بشكل متساوي دون كسور

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

ويمكنك حساب باقي القسمة بشكل يدوي عن طريق ايجاد قسمة 3 / 2 ستحصل على 1.5 الرقم الصحيح هو 1 والكسر المتبقي هو 0.5
الآن عندما تضرب العدد الكسري 0.5 المتبقي المعامل الثاني وهو 2 الناتج سيكون 1 وهو باقي القسمة

مثال أخر 8 % 4 لحساب باقي القسمة أول شيء أحسب ناتج القسمة 8 / 4 ستحصل على 2
وهو عدد صحيح ليس به أي كسر وهذا يعني أن باقي القسمة 8 % 4 هو 0

ملحوظة: عندما تقوم بقسمة عددين والناتج يكون عدد صحيح بدون كسر فهذا يعني أن باقي القسمة هو 0
وهذا يعني أن العدد الأول يقبل القسمة على العدد الثاني أو أنه من مضاعفات العدد التاني
فإذا كان 8 % 4 تساوي 0 إذًا الرقم 8 يقبل القسمة على 4 بدون باقي وهذا يعني أن 8 هو من مضاعفات العدد 4
وهكذا مع كل شئ مثل 9 % 3 ستجد أن الناتج هو 0 وهذا يعني أن الرقم 9 يقبل القسمة على 3 بدون باقي وهو من مضاعفات العدد 3

هناك طرق عديدة لحساب باقي القسمة وهي سنستخدم مثال أخر 19 % 5 ونطبق الطرق المختلفة عليها

نمط نواتج باقي القسمة

الناتج الخاص بباقي القسمة لأي عدد له نمط معين وأريدك أن تكتشفه

لنحسب باقي القسمة الأرقام من 0 إلى 10 للرقم 2 ونرى النمط الذي يحدث

0 % 2 = 0
1 % 2 = 1
2 % 2 = 0
3 % 2 = 1
4 % 2 = 0
5 % 2 = 1
6 % 2 = 0
7 % 2 = 1
8 % 2 = 0
9 % 2 = 1
10 % 2 = 0

هل لاحظت النمط الذي حدث ؟
النواتج محصورة بين 0 و 1 فقط وهذا يعني أن باقي القسمة لأي عدد على 2 سيكون إما 0 أو 1 فقط

دعنا نحسب الأرقام من 0 إلى 10 للرقم 3 ونرى النمط الذي يحدث

0 % 3 = 0
1 % 3 = 1
2 % 3 = 2
3 % 3 = 0
4 % 3 = 1
5 % 3 = 2
6 % 3 = 0
7 % 3 = 1
8 % 3 = 2
9 % 3 = 0
10 % 3 = 1

هل لاحظت النمط مجددًا ؟
النواتج محصورة بين 0 و 1 و 2 فقط وهذا يعني أن باقي القسمة لأي عدد على 3 سيكون إما 0 أو 1 أو 2 فقط

دعونا نرى مع الرقم 7

0 % 7 = 0
1 % 7 = 1
2 % 7 = 2
3 % 7 = 3
4 % 7 = 4
5 % 7 = 5
6 % 7 = 6
7 % 7 = 0
8 % 7 = 1
9 % 7 = 2
10 % 7 = 3

ستلاحظ أن الناتج يكون محصور بين 0 و n - 1 حيث n هو الرقم الذي تقوم بقسمة العدد عليه
بالتالي باقي قسمة أي رقم على 12 الناتج سيكون محصور بين 0 و 11 فقط
وباقي قسمة أي رقم على 50 الناتج سيكون محصور بين 0 و 49 فقط
وباقي قسمة أي رقم على 1458 الناتج سيكون محصور بين 0 و 1457 فقط
... وهكذا

بعض فوائد باقي القسمة في البرمجة

باقي القسمة له استخدامات متعددة ومفيدة جدًا في البرمجة ويحل لنا مسائل كثيرة بطرق بسيطة وسهلة
وقد نحتاج لمقالة كاملة لنتحدث عنها وعن تطبيقاتها ونحل بعض المسائل البرمجية باستخدامها

معرفة الأعداد الزوجية والفردية

على سبيل المثال إذا اعطيتك رقم عشوائيًا مثل 6 وقلت لك هل هذا الرقم زوجي أم فردي؟
ستقول لي بسيطة الرقم 6 هو رقم زوجي، أنت عرفت هذا لأنك ما شاء الله عليك بني آدم ذكي وتعرف ذلك بسرعة
لكن لغة البرمجة كيف لها أن تعرف هذا؟

السؤال هنا كيف عرفت أنت أن الرقم 6 هو زوجي؟
الجواب بسيط جدًا لأنك تعرف أن الأعداد الزوجية هي التي تقبل القسمة على 2 بدون باقي
والأعداد الفردية هي التي إذا قسمتها على على 2 وتحصل على عدد به كسور

إذا ففي البرمجة نستطيع أن نعرف إذا كان الرقم زوجي أم فردي بسهولة عن طريق باقي القسمة

int number = 6;
int is_even = number % 2 // 0

هنا قمنا بحساب باقي قسمة الرقم 6 على 2 وبما أن الناتج 0 إذًا الرقم 6 هو زوجي

int number = 7;
int is_even = number % 2 // 1

هنا قمنا بحساب باقي قسمة الرقم 7 على 2 وبما أن الناتج 1 وليس 0 إذًا الرقم 7 هو فردي

حساب أنماط الأوقات والأيام

وأيضًا يفيدنا في حساب الأنماط العددية التي تكرر بشكل دوري كوقت والأيام وغيرها
فمثلا في الساعة إذا كانت الساعة الآن 18 وقلت لك كم الساعة الآن على مقياس 12 ساعة ؟
ستقول لي بسيطة الساعة الآن 6 لأنك تعرف أن الساعات تكرر كل 12 ساعة بالتالي 18 - 12 = 6
حسنا إذا كانت الساعة الآن 34 وقلت لك كم الساعة الآن على مقياس 12 ساعة ؟
قد تقوم بحسابها بشكل يدوي وتقول لي الساعة الآن 10 لأن 34 - 12 - 12 = 10

ماذا إذا زاد الرقم وأصبح 110 وقلت لك كم الساعة الآن على مقياس 12 ساعة ؟ سيكون الأمر صعبًا أليس كذلك
لكن في البرمجة يمكننا حسابها بسهولة عن طريق باقي القسمة كيف ذلك ؟

عندما قلت لك أن الساعة الآن 34 وقلت لي أن الساعة الآن على مقياس 12 ساعة ستكون 10
حسنًا الساعة تتكرر كل 12 لذا لكي تعرف كم يساوي الرقم 34 على مقياس 12 ساعة
عليك أن تطرح منه 12 حتى تحصل على الرقم 10
هذا هو مفهوم باقي القسمة أنك تحاول تقسيم الرقم 34 على 12 وترى كم سيتبقى معك

int hour = 34;
int hour_12 = hour % 12; // 10

هنا قمنا بقسمة الرقم 34 على 12 وحصلنا على الناتج 10 وهو الساعة الآن على مقياس 12 ساعة
هكذا يمكننا حل أي مسألة مشابهة عن طريق إيجاد باقي القسمة

الأمر لا يختصر على السعات بل يمكن تطبيق نفس الفكرة على الأيام والأشهر والأعوام وغيرها من الأنماط العددية التي تتكرر بشكل دوري


إليك سؤال مختلف قليلًا إذا سألك أحد وقال لك الساعة الآن 7 وقال لك كم ستكون الساعة بعد 15 ساعة ؟ على مقياس 12 ساعة
كيف ستحل هذه المسألة ؟

سنتبع نفس المبدأ فقط الاختلاف أنك ستجمع 7 و 15 ثم ترى الناتج كيف سيكون على مقياس 12 ساعة

int current_hour = 7;
int after_hour = 15;
int hour_12 = (current_hour + after_hour) % 12; // 10

هنا قمنا بجمع الساعة الحالية 7 مع الساعات الزائدة الذي أرادها 15 وحصلنا على الناتج 22 ثم قمنا بحساب باقي قسمة 22 على 12 لنحصل على 10 وهو الساعة الآن على مقياس 12 ساعة


لو اليوم كان يوم الثلاثاء وقلت لك بعد 45 يوم سيكون أي يوم من أيام الأسبوع ؟
يوم الثلاثاء هو اليوم رقم 3 في الأسبوع وبعد 45 يوم سيكون اليوم رقم 48
بالتالي يمكننا حساب اليوم بعد 45 يوم بسهولة عن طريق باقي القسمة

int current_day = 3;
int after_day = 45;

int day = (current_day + after_day) % 7; // 6

هنا قمنا بجمع اليوم الحالي 3 مع الأيام الزائدة الذي أرادها 45 وحصلنا على الناتج 48
ثم قمنا بحساب باقي قسمة 48 على 7 لنحصل على 6 وهو يمثل يوم الجمعة
وهكذا يمكننا حل أي مسألة مشابهة بسهولة


ملحوظة: المثال الأخير هو مجرد حيلة نستخدمها لحل معضلة ما في باقي القسمة
وهي أننا نحاول تحويل نطاق النواتج الخاص بباقي القسمة من 0 إلى n - 1 إلى 1 إلى n
وهذا المثال مجرد توسيع افاق مع باقي القسمة وليس له علاقة بفهم مفهوم باقي القسمة بحد ذاتها

ستلاحظ هنا شيئًا أن في مثال الساعة عندما تكون الساعة 12 وقلت لك كم الساعة على مقياس 12 ساعة ستجيب لي بـ 0
لأن 12 % 12 = 0
لكن كمنظور بشري لا يوجد ساعة 0 فكيف يمكننا حل هذه المشكلة ؟

قلنا أن باقي قسمة أي رقم على n سيكون محصور بين 0 و n - 1
بالتالي قسمة أي رقم على 12 سيكون الناتج محصور بين 0 و 11

12 % 12 = 0
1 % 12 = 1
2 % 12 = 2
3 % 12 = 3
4 % 12 = 4
5 % 12 = 5
6 % 12 = 6
7 % 12 = 7
8 % 12 = 8
9 % 12 = 9
10 % 12 = 10
11 % 12 = 11

لكن لو أردنا أن نحصل على الناتج بين 1 و 12 ماذا نفعل ؟

قد تقول لي بسيطة نقوم بإضافة 1 إلى الناتج النهائي وهكذا سيكون الناتج بين 1 و 12
حسنًا لنجرب هذا

int hour = 12;
int hour_12 = (hour % 12) + 1; // 1

لقد اضفنا 1 على ناتج 12 % 12 وحصلنا على الناتج 1 وهذا خطأ
لأنك لم تحل المشكلة بشكل صحيح كل ما فعلته هو إضافة 1 على الناتج النهائي وهذا ما يحدث

12 % 12 = 0  --> 0 + 1 = 1
1 % 12 = 1  --> 1 + 1 = 2
2 % 12 = 2  --> 2 + 1 = 3
3 % 12 = 3  --> 3 + 1 = 4
4 % 12 = 4  --> 4 + 1 = 5
5 % 12 = 5  --> 5 + 1 = 6
6 % 12 = 6  --> 6 + 1 = 7
7 % 12 = 7  --> 7 + 1 = 8
8 % 12 = 8  --> 8 + 1 = 9
9 % 12 = 9  --> 9 + 1 = 10
10 % 12 = 10 --> 10 + 1 = 11
11 % 12 = 11 --> 11 + 1 = 12

أنت بالفعل جعلت الناتج بين 1 و 12 لكنك قمت بعمل ازاحة
فالرقم 12 أصبح 1 والرقم 1 أصبح 2 والرقم 2 أصبح 3 وهكذا
ونحن لا نريد هذا نحن نريد أن نحصل على الرقم 12 كما هو بدلًا من أن يصبح 0

بصراحة إضافة 1 إلى الناتج النهائي هو نصف الحل فقط ونحن نحتاج لعمل ازاحة فعًلا
لكن قبل الازاحة تلك لنرى هذه الحيلة

1 % 12 = 1
2 % 12 = 2

2 % 12 = (1 % 12) + 1

هل لاحظت شيئًا ؟

إذا قمت بحساب باقي قسمة 1 على 12 ستجد أن الناتج يكون نفسه باقي قسمة 0 على 12 زائد 1 (الازاحة التي قمنا بها)

لنجرب مثال آخر

6 % 12 = 6
7 % 12 = 7

7 % 12 = (6 % 12) + 1

هنا نستطيع الخروج بمعادلة بسيطة وهي (x - 1) % n + 1 وهذه المعادلة تعطينا الناتج بين 1 و n بدلًا من أن يكون بين 0 و n - 1
الفكرة فيها أننا طالما 12 % 12 يعطينا 0 و 11 % 12 يعطينا 11 فلما لا نحسب 11 % 12 ونضيف 1 للناتج لنحصل على 12
نأتي بالناتج الذي قبله ونضيف له واحد هكذ نحصل على الناتج النهائي بين 1 و 12

لنجرب هذه المعادلة على الساعات

(x - 1) % n + 1
n = 12
x = 1 ... 12

(1 - 1) % 12 + 1 = 0 + 1 = 1
(2 - 1) % 12 + 1 = 1 + 1 = 2
(3 - 1) % 12 + 1 = 2 + 1 = 3
(4 - 1) % 12 + 1 = 3 + 1 = 4
(5 - 1) % 12 + 1 = 4 + 1 = 5
(6 - 1) % 12 + 1 = 5 + 1 = 6
(7 - 1) % 12 + 1 = 6 + 1 = 7
(8 - 1) % 12 + 1 = 7 + 1 = 8
(9 - 1) % 12 + 1 = 8 + 1 = 9
(10 - 1) % 12 + 1 = 9 + 1 = 10
(11 - 1) % 12 + 1 = 10 + 1 = 11
(12 - 1) % 12 + 1 = 11 + 1 = 12

أنظر الآن كيف أننا حصلنا على الساعات بين 1 و 12 بدلًا من أن تكون بين 0 و 11

لنجرب هذه المعادلة ككود برمجي

int hour = 12;
int hour_12 = ((hour - 1) % 12) + 1; // 12

hour = 6;
hour_12 = ((hour - 1) % 12) + 1; // 6

hour = 1;
hour_12 = ((hour - 1) % 12) + 1; // 1

هنا وصلنا لهدفنا وهو الحصول على الساعة بين 1 و 12 بدلًا من أن تكون بين 0 و 11
عن طريق معادلة بسيطة وهي (x - 1) % n + 1 حيث x أكبر من

اختصارات العمليات الحسابية

سنشرح الآن بعض الاختصارات التي تقدمها لغات البرمجة لتسهيل عليك كتابة بعض الحسابات
مثل ++ و -- و += و -= و *= و /=

في معظم لغات البرمجة، عندما نريد جمع متغيرات أو أرقام، نستخدم علامة +

int x = 5;
x = x + 1;

// x = 6

في هذا المثال، نحن فقط نضيف الرقم 1 للمتغير x

لكن لتبسيط الأمور وتوفير الوقت، قدمت معظم لغات البرمجة طرقًا مختصرة للقيام بنفس العملية

استخدام علامة +=

علامة += تعني جمع القيمة التي في يمين العلامة = مع المتغير الذي في اليسار، والناتج يخزن في المتغير

int x = 5;
x += 1;

// x = 6

السطر x += 1 هو اختصار لـ x = x + 1، وهذا يساعد في تقليل تكرار كتابة المتغير

يمكنك أيضًا إضافة أي رقم تريده باستخدام هذه العلامة:

int x = 5;
x += 10;
x += 20;

// x = 35

استخدام علامة ++

نظرًا لأن إضافة الرقم 1 شيء شائع جدًا في البرمجة، قدمت معظم اللغات طريقة مختصرة لزيادة المتغير بقيمة 1 باستخدام ++

int x = 5;
x++;

// x = 6

السطر x++ هو اختصار لـ x = x + 1 أو x += 1

يمكنك استخدام ++ قبل أو بعد المتغير:

int x = 5;
x++;
++x;

// x = 7

في هذه الحالة، لا يوجد فرق بين x++ و ++x
نحن فقط نجمع الرقم 1 على المتغير x، ولكن في حالات أخرى، يكون الفرق كبيرًا

الفرق بين x++ و ++x

الفرق الأساسي بينهما هو:

يمكن رؤية الفرق في الأمثلة التالية:

int x = 5;
int y = x++;

// x = 6
// y = 5

في السطر الأول، قمنا بتعريف المتغير x بقيمة 5
في السطر الثاني، قمنا بتعريف المتغير y وجعلناه يساوي x++

هنا مع x++ أول شيء سيحصل هو أن المتغير y سيأخذ قيمة x الحالية لتصبح قيمة y تساوي 5
ثم يتم زيادة x بـ 1 لتصبح قيمة x الجديدة تساوي 6

هكذا تكون قيمة y تساوي 5 وقيمة x تساوي 6


أما مع ++x فالأمر يكون مختلفًا

int x = 5;
int y = ++x;

// x = 6
// y = 6

هنا مع ++x أولاً ستزيد قيمة المتغير x بـ 1 لتصبح قيمة xالجديدة تساوي 6
ثم يتم اسناد القيمة الجديدة لـ x إلى المتغير y لتصبح قيمة y تساوي 6

هذا هو الفرق الأساسي بين x++ و ++x

فمع x++ يتم إرجاع القيمة القديمة ثم زيادة 1، أما في ++x يتم زيادة 1 ثم إرجاع القيمة الجديدة

علامات أخرى مشابهة لـ += و ++

معظم اللغات لا تقتصر على += و ++ فقط، بل تقدم مجموعة من الرموز الأخرى لتسهيل العمليات الشائعة مثل الطرح والقسمة والضرب:

والكثير من العلامات الأخرى التي تقدمها لغات البرمجة لتسهيل العمليات الحسابية
كل ما عليك فعله هو تعلم اللغة التي تدرسها والتعرف على الرموز والمميزات التي تقدمها تلك اللغة لك

ترتيب أولية العملية

في البرمجة هناك ترتيب أولية للعمليات الحسابية

بمعنى عندما تجد معادلة مثل 5 + 3 * 2 أي العملية التي يجب أن تحسب أولًا ؟ الجمع أم الضرب ؟
الجواب هو الضرب يتم حسابه أولًا ثم الجمع

وهذا يحدث لأن الضرب لديه أولوية أعلى من الجمع

وهناك ترتيب أولية للعمليات الحسابية وهي كالتالي:

إذا قابلت عمليات بنفس الأولية مثل * و % في نفس السطر تقوم بالحساب من اليسار إلى اليمين

int result = 5 + 3 * 2; // 11

هنا قمنا بحساب الضرب أولًا 3 * 2 وحصلنا على الناتج 6 ثم قمنا بالجمع 5 + 6 وحصلنا على الناتج 11

int result = 5 * 3 % 2; // 1

لدينا هنا عمليتين الضرب وباقي القسمة بنفس الأولية لذا نحسب من اليسار إلى اليمين
لذا نحسب الضرب أولًا 5 * 3 الناتج 15 ثم نحسب باقي القسمة 15 % 2 والناتج 1

int result = 5 * (3 + 2); // 25

هنا الأولية هي حساب العمليات التي بداخل الأقواس أولًا 3 + 2 الناتج 5 ثم نقوم بالضرب 5 * 5 والناتج 25

int x = 5;
int result = ++x * 3 + 2; // 20

هنا الأولية هي حساب العمليات التي تحتوي على ++ و -- أولًا ++x ستكون 6 ثم نقوم بالضرب 6 * 3 الناتج 18 ثم نقوم بالجمع 18 + 2 الناتج 20

العمليات الحسابية على القيم المنطقية

تعرفنا في مقالات سابقة على نوع البيانات المهتم بالقيم المنطقية التي تسمى boolean وهي القيم التي تأخذ قيمتين فقط true و false وهناك العديد من العمليات التي يمكننا القيام بها على هذه القيم المنطقية مثل عمليات المقارنة التي تستخدم < و > و == و != و <= و >= وغيرها وعمليات البوابات المنطقية مثل AND و OR و NOT وغيرها وسنتعرف عليها بالتفصيل الآن

عمليات المقارنة

هذه العمليات تقوم بمقارنة قيمتين معًا وتعطيك قيمة boolean أي true أو false وهذه العمليات تستخدم بشكل أساسي في البرمجة في عمل بعض الشروط والقيود والمقارنات مثل:

كل تلك الأمور يمكنك القيام بها بسهولة عن طريق عمليات المقارنة مع الـ boolean وهناك العديد من عمليات المقارنة ومنها < و > و == و != و <= و >= وغيرها وسنتعرف عنها بالتفصيل تاليًا

أكبر من > وأصغر من <

لغات البرمجة تساعدك في عمل مقارنة بين قيمتين لمعرفة هل أي الرقمين أكبر من الآخر أو أصغر من الآخر فهنا تأتي دور عمليتين الأكبر من > والأصغر من <

int ahmed_age = 24;
int kamal_age = 18;

bool isAhmedOlderThanKamal = ahmed_age > kamal_age; // true

bool isKamalOlderThanAhmed = kamal_age < ahmed_age; // true

هنا لدينا قيم تمثل أعمار شخصين أحدهم يدعى أحمد والآخر يدعى كمال خزناهم في متغيرين ahmed_age و kamal_age
ونريد أن نعرف هل أحمد أكبر من كمال أم العكس

لذا قمنا بعملية المقارنة بين العمرين ahmed_age > kamal_age وحصلنا على الناتج true لأن أحمد أكبر من كمال
وفي السطر الثاني قمنا بعملية المقارنة بين العمرين kamal_age < ahmed_age وحصلنا على الناتج true لأن كمال أصغر من أحمد

إذا قمنا بعكس العلامة بالطبع ستحصل على قيم false

bool isAhmedOlderThanKamal = ahmed_age < kamal_age; // false
bool isKamalOlderThanAhmed = kamal_age > ahmed_age; // false

هنا قمنا بعكس العلامة في السطر الأول وحصلنا على الناتج false لأن أحمد ليس أصغر من كمال
وفي السطر الثاني قمنا بعكس العلامة وحصلنا على الناتج false لأن كمال ليس أكبر من أحمد

ولاحظ أن ناتج عملية المقارنة هي قيمة boolean إما true أو false لذا وضعنا الناتج في متغيرات من نوع boolean مثل isAhmedOlderThanKamal و isKamalOlderThanAhmed


أيضًا معظم اللغات تسمح لك بالقيام بالمقارنة بين نصوص من نوع string أو char
ذكرنا أن كل حرف أو رمز يقابله رقم في جدول الـ ASCII فالحرف A يقابله الرقم 65 والحرف a يقابله الرقم 97 وهكذا

لذا عندما نقارن بين الحروف تقوم لغات البرمجة بمقارنة الأرقام التي تقابلها في جدول الـ ASCII

char first_char = 'A';
char second_char = 'B';
char third_char = 'C';

bool isALessThanB = first_char < second_char; // true
bool isCLessThanA = third_char < first_char; // false

هنا قمنا بعملية المقارنة بين الحروف A و B وقلنا هل A أصغر من B وكانت النتيجة true
لأن في جدول الـ ASCII الحرف A قيمته 65 والحرف B قيمته 66 وبالتالي A أقل من B

وفي السطر الثاني قمنا بعملية المقارنة بين الحروف C و A وقلنا هل C أصغر من A وكانت النتيجة false لأن قيمة C في جدول الـ ASCII هي 67 وقيمة A هي 65 وبالتالي C أكبر من A فيأتي بعده

int one = 1;
char zero = '0';

bool isOneGreaterThanZero = one > zero; // false

هنا سؤال مخادع قليلًا هل الرقم 1 أكبر من الحرف '0' ؟
الجواب هو false لأن الحرف '0' في جدول الـ ASCII يقابله الرقم 48 بتالي عندما نقول 1 > '0' فهذا يترجم إلى 1 > 48 بالتالي الناتج false لأن 1 أصغر من 48


نفس الشيء مع الـ string

string name_1 = "Ahmed";
string name_2 = "Kamal";

bool isAhmedGreaterThanKamal = name_1 > name_2; // false

هنا قمنا بعملية المقارنة بين Ahmed و Kamal وقلنا هل Ahmed أكبر من Kamal وكانت النتيجة false
كيف يتم ذلك ؟

هنا اللغة تقارن حرف حرف من اليسار إلى اليمين وتقارن الحروف بحسب قيمها في جدول الـ ASCII
عندما بدأت المقارنة بين الحرف الأول من كل اسم A و K وجدت أن A أصغر من K وبالتالي توقفت المقارنة وأعطتني النتيجة false

string text_1 = "abcab";
string text_2 = "ababababababab";

bool isText1GreaterThanText2 = text_1 > text_2; // true

هنا قمنا بعملية المقارنة بين abcab و ababababababab وقلنا هل abcab أكبر من ababababababab وكانت النتيجة true
كيف يتم ذلك ؟ برغم أن abcab أقل من ababababababab من حيث الطول

هذا بسبب أن اللغة كما قلنا تقارن تقارن حرف حرف
فبدأت المقارنة بين الحرف الأول من كل نص a و a وجدت أنهما متساويين
ثم انتقلت إلى الحرف الثاني من كل نص b و b وجدت أنهما متساويين
ثم عندما وصلت إلى الحرف الثالث من كل نص c و a وجدت أن c في النص الأول أكبر من a وبالتالي توقفت المقارنة وأعطتني النتيجة true دون أن تكمل

أكبر من أو يساوي >= وأصغر من أو يساوي <=

لا داعي لأن اشرح شيء هنا لا توجد فكرة جديدة هنا
كل شيء قلناه عن < و > ينطبق هنا أيضًا مع زيادة أنه يأخذ في الاعتبار القيم المتساوية

فقط تذكر أنها تكتب هكذا >= و <= بدون مسافة ولا تكتبها هكذا => و =< بل هكذا >= و <=

int x = 5;

bool isXLessThanOrEqual5 = x <= 5; // true
bool isXGreaterThanOrEqual5 = x >= 5; // true

// ❌ في حالة عكست ترتيب العلمتين ستحصل على خطأ
bool wrongOrder_1 = x => 5; // Syntax Error
bool wrongOrder_2 = x =< 5; // Syntax Error

فيجب أن تتذكر فقط الترتيب الصحيح للعلامات

ويمكنك تذكر ترتيب هذه العلامات بنفس ترتيب نطق كلماتها في الجملة
مثلاً >= نحن نقول أكبر من أو يساوي هكذا ستكتب العلامة > ثم = من اليسار لليمين
وهكذا مع <= نقول أصغر من أو يساوي ولا أظن أن هناك أحدًا يقول يساوي أو أصغر من ... أليس كذلك ؟ .. أرجوا

لماذا قد أكون بالغت في شرح هذه التفصيلة ؟ لأنني كنت دائمًا أخطئ في كتابة هذه العلامات وأنا أتعلم البرمجة لكن بعد ما شركتها لنفسي بهذا الشكل لم أخطئ في كتابتها مرة أخرى

المساواة == و ===

هذه العملية تقوم بمقارنة قيمتين معًا وتعطيك true إذا كانت القيمتين متساويتين وتعطيك false إذا كانت القيمتين غير متساويتين

bool equal_1 = 5 == 5; // true
bool equal_2 = 5 == 6; // false

هنا قمنا بمقارنة العددين 5 و 5 وحصلنا على الناتج true لأن العددين متساويين
وفي السطر الثاني قمنا بمقارنة العددين 5 و 6 وحصلنا على الناتج false لأن العددين غير متساويين

عليك أن تفرق بين = و == فالأولى تستخدم لتعيين قيمة لمتغير والثانية تستخدم للمقارنة بين قيمتين

int x = 5; // تعيين قيمة

bool equal = x == 5; // مقارنة قيمة

لاحظ أن = نستخدم لاسناد أو تعيين قيمة لمتغير مثل ما فعلنا في السطر الأول x = 5 هكذا المتغير x قيمته أصبحت تساوي 5
و == نستخدم للمقارنة بين قيمتين مثل ما فعلنا في السطر الثاني x == 5 وهذا يعني هل قيمة x تساوي 5 ؟ والناتج يكون true أو false

bool equal = x == 5;

لاحظ أنه يقوم بعمل المقارنة x == 5 أولًا ثم الناتج يتم اسناده وتعينه في المتغير equal


سؤال هل 0 تساوي '0' ؟

bool equal = 0 == '0';

في معظم لغات البرمجة الناتج هنا false لأن العدد 0 لا يساوي الحرف '0' الذي يقابله الرقم 48 في جدول الـ ASCII
لكن في هناك لغات مثل JavaScript تعتبر الناتج هنا true لأنها لا تهتم بنوع القيمة وتقوم بتحويل القيمة تلقائيًا لتوحيدهما وتقارنهما
بمعنى أن في لغة JavaScript ناتج 0 == '0' يكون true

لغة JavaScript قدمت لنا === للمقارنة بين القيمتين ومراعاة نوع القيمة أي أنها تقوم بالمقارنة بين القيمتين ونوعهما

let equal_1 = 0 == '0'; // true
let equal_2 = 0 === '0'; // false

هنا في السطر الأول قمنا بمقارنة العدد 0 والحرف '0' باستخدام == وحصلنا على true لأن JavaScript هنا قارنت بغض النظر عن نوع القيمة لأننا استخدمنا ==
وفي السطر الثاني قمنا بمقارنة العدد 0 والحرف '0' باستخدام === وحصلنا على false لأن JavaScript هنا قارنت القيم وراعت نوع القيمة لأننا استخدمنا ===


ستجد أن اللغات قد تعامل الأمور بشكل مختلف في هذا الجانب فبعضها تهتم بنوع القيمة وبعضها لا تهتم بنوع القيمة
لذا ادرس اللغة التي تتعلمها وافهم كيف تتعامل مع القيم والمقارنات بين انواع البيانات المختلفة

عدم المساواة !=

لا أظن أن هناك شيء جديد هنا يجب شرحه
لأنه ببساطة العلامة != هي العكس تمامًا من == تقوم بمقارنة قيمتين معًا وتعطيك true إذا كانت القيمتين غير متساويتين وتعطيك false إذا كانت القيمتين متساويتين

bool notEqual_1 = 5 != 5; // false
bool notEqual_2 = 5 != 6; // true

هنا قمنا بمقارنة العددين 5 و 5 وحصلنا على الناتج false لأن العددين متساويين
وفي السطر الثاني قمنا بمقارنة العددين 5 و 6 وحصلنا على الناتج true لأن العددين غير متساويين


هذه هي عمليات المقارنة الأساسية الشائعة التي ستجدها في معظم اللغات
لكن هذا لا يمنع أنك قد تجد لغات تستخدم رموز وانواع وطرق مختلفة وجديدة للمقارنة بين القيم
مثل في Python تجد أنها تستخدم is و is not

عمليات البوابات المنطقية

هل تتذكر البوابات المنطقية في الفيزياء الحديثة ؟
البوابات المنطقية هي مجموعة العملية التي كانت في التحكم بمسار الكهرباء في الدوائر الكهربية
أما في البرمجة فنستخدمها مع القيم المنطقية الـ boolean لعمل بعض الشروط والتحقق من القيود

نحن كنا نعرف المتغير من نوع boolean ونضع له شرط واحد فقط

int age = 24;
bool isYoung = age < 30; // true

ماذا إذا أردنا أن نضع أكثر من شرط ؟
مثل إذا كان الشخص طالب جامعي ويردي نظارات وذكي هنا نستخدم البوابات المنطقية للتحقق من أكثر من شرط

هناك العديد من البوابات المنطقية الأساسية لكن سنكتفي بالأساسية الأربعة وهي AND و OR و NOT و XOR

يمكننا بناء جدول يوضح لنا القيم المتوقعة لكل بوابة منطقية

الشرط الأول (A) الشرط الأول (B) A AND B A OR B NOT A NOT B A XOR B
true true true true false false false
true false false true false true true
false true false true true false true
false false false false true true false

لاحظ بعض النقاط المهمة هنا:

عملية الـ AND

الشرط الأول (A) الشرط الأول (B) A AND B
true true true
true false false
false true false
false false false

هذه العملية تستخدم للتحقق من صحة كلا شرطين معًا وتعطيك true إذا كان كلا الشرطين صحيحين وتعطيك false إذا كان أحدهما خطأ
تخيل أن معك مصباح له زرين لا يضيء إلا عندما تضغط على زرين معًا وإذا ضغطت على زر واحد فقط لن يعمل المصباح

ورمزها في لغات البرمجة هو && بعض اللغات قد تستخدم and

int age = 24;
bool isStudent = true;

bool isYoungAndStudent = age < 30 && isStudent; // true

لاحظ أننا هنا قمنا بعملية AND بين شرطين age < 30 و isStudent وحصلنا على الناتج true لأن age < 30 تعطينا true و isStudent قيمتها true
إذا true && true تعطينا true
ولاحظ أننا فصلنا بين الشرطين بعلامة && وهذا يعني


int x = 5;
int y = 10;

int z = 11;
bool middle = z > x && z < y; // false

هنا قمنا بعملية AND بين شرطين z > x و z < y وحصلنا على الناتج false لأن z > x تعطينا true و z < y تعطينا false
إذا true && false تعطينا false


هل يمكننا استخدام AND مع أكثر من شرطين ؟
نعم نحن كنا نستخدم شرطين لتبسيط الأمور ولكن يمكنك استخدام AND مع أكثر من شرطين

string name = "Ahmed";
int age = 24;
bool isStudent = true;

bool isSmartMan = name == "Ahmed" && age >= 24  && isStudent; // true

هنا قمنا بعملية AND بين ثلاث شروط name == "Ahmed" و age >= 24 و isStudent وحصلنا على الناتج true لأن كل الشروط صحيحة


إذا كان هناك شرط واحد فقط خطأ فإن الناتج بأكمله سيكون false

string name = "Ahmed";
int age = 24;
bool isStudent = false;

bool isSmartMan = name == "Ahmed" && age >= 24  && isStudent; // false

هنا بسبب أن isStudent قيمتها false فإن الناتج بأكمله سيكون false حتى ولو كان الشرطين الآخرين صحيحين لأننا نستخدم AND وهذا يعني أن كل الشروط يجب أن تكون صحيحة لتعطينا true

عملية الـ OR

الشرط الأول (A) الشرط الأول (B) A OR B
true true true
true false true
false true true
false false false

تستخدم هذه العملية للتحقق من صحة أحد الشرطين أو كليهما وتعطيك true إذا كان على الأقل أحد الشرطين على الأقل صحيحًا وتعطيك false فقط عندما يكون كلا الشرطين خاطئين
تخيل تملك مصباح له زرين ويضيء عندما تضغط على أي زر

رمزها في لغات البرمجة || وبعض اللغات البرمجة تستخدم or

int age = 12;
bool isSuperSmartKid = true;

bool canEnterCollege = age >= 24 || isSuperSmartKid; // true

لاحظ هنا أن الشرط الأول age >= 24 أعطى false لكن بسبب أن isSuperSmartKid قيمته true فإنا الناتج الكلي سيصبح true
لأن الـ OR تشترط أن يكون شرط واحد فقط يغطي true لتعطيك true


والحالة الوحيدة التي تعطيك false هي عندما يكون كلا الشرطين خاطئين

int age = 12;
bool isSuperSmartKid = false;

bool canEnterCollege = age >= 24 || isSuperSmartKid; // false

هنا بسبب أن كلا الشرطين age >= 24 و isSuperSmartKid قيمتهما false فإن الناتج الكلي سيكون false

عملية الـ NOT

الشرط (A) NOT A
true false
true false
false true
false true

تستخدم هذه العملية لعكس ناتج الشرط فإن كان الشرط يعطيك true فقيمته بعد الـ NOT سيكون false
رمزها في لغات البرمجة هو ! وبعض اللغات البرمجة تستخدم not

int age = 30;

bool isAdult = !(age > 24);

ما هو الناتج هنا برأيك ؟
الشرط age > 24 سيعطينا true لأن age أكبر من 24 ولكن بسبب أننا استخدمنا ! فإن الناتج سيكون false
المعادلة كانت !(age > 24) ثم اصبحت هكذا !(true) بالتالي الناتج النهائي سيكون false
لأن الـ NOT تعكس النتيجة فإذا كان الشرط يعطيك true فإن الـ NOT سيعطيك false والعكس صحيح

عملية الـ XOR

الشرط الأول (A) الشرط الأول (B) A XOR B
true true false
true false true
false true true
false false false

يمكنك أن تقول أنها تحب الاختلاف وتكره المساواة والتشابه
بمعنى أنها تعطيك true فقط عندما يكون الشرطين مختلفين وتعطيك false عندما يكون الشرطين متساويي ومتشابهين
ورمزها في لغات البرمجة ^

bool xorExample_1 = true ^ true; // false
bool xorExample_2 = false ^ false; // false

bool xorExample_3 = true ^ false; // true
bool xorExample_4 = false ^ true; // true

لاحظ أنها تعطيك false عندما يكون الشرطين متساويين وتعطيك true عندما يكون الشرطين مختلفين
الـ XOR تفيدنا في التحقق من الاختلاف خصوصًا التحقق من شيئين يناقضا بعضهما
بحيث ان كان هناك تشابه بين النقيضين فإن الناتج يكون false وإذا كان هناك اختلاف بينهما فإن الناتج يكون true


bool isTall = true;
bool isShort = true;

bool isLogical = isTall ^ isShort; // false

هنا لدينا متغير يمثل هل الشخص طويل isTall ومتغير يمثل هل الشخص قصير isShort وكلا المتغيرين ينقضان بعضهما، لا أظن أن هناك شخص سيكون طويل وقصير في نفس الوقت

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

هنا قمنا بعملية XOR بين شرطين isTall و isShort وحصلنا على الناتج false لأن الشرطين متساويين
كأنها وسيلة للتحقق بين نقيضين مثل isTall و isShort ولا يمكنهما أن يكونا متساويين

بدون استخدام XOR كيف كنا سنحسب الشرط السابق في isLogical ؟

bool isLogical = (isTall && !isShort) || (!isTall && isShort)

هل ترى تلك العملية الطويلة ؟ هذه العملية من أجل التحقق من:

ثم نجمعهما في || لنرى هل هناك تناقض أم لا ليكون شكل المعادلة النهائية هكذا (isTall && !isShort) || (!isTall && isShort)
الـ XOR تسهل وتختصر علينا هذه العملية وتجعلها أقصر وأسهل isTall ^ isShort

هذه المعادلة هي ترجمة للـ XOR باستخدام AND و OR و NOT فقط
ولكن في حقيقة هناك شكل آخر لترجمة الـ XOR باستخدام != وهو كالتالي isTall != isShort

bool isLogical = isTall != isShort;

لكن هذا فقط حين نتعامل مع القيم المنطقية true و false ولكن في حالة الأرقام فيجب عليك استخدام الـ XOR مباشرة والرمز ^ الخاص بها
ستفهم ما اقصد عندما تقرأ الفضفضة التالية

عمليات البوابات المنطقية على الأرقام الثنائية

ملحوظة: هذا الجزء ليس ضروريًا لفهم الأمور الأساسية في البرمجة ويمكنك تخطيه لذا سأفصله في مقالة أو فضفضة قصيرة بعيدًا عن المقالات الأساسية
يمكنك قراءة الفضفضة من هنا عمليات البوابات المنطقية على الأرقام الثنائية