شناخت پنج عملگر حسابی `+`، `-`، `*`، `/`، `%` و تفاوت «عملگر» (Operator) با «عملوند» (Operand)
درک قانون مهم `int / int = int` و روش گرفتن خروجی اعشاری با تبدیل نوع (Type Casting)
آشنایی با عملگر باقیمانده `%` و استفاده از آن برای استخراج ارقام یک عدد
یادگیری تبدیل نوع ضمنی (Implicit) و صریح (Explicit) با `float(n)` و `(double)n`
ترجمه فرمولهای ریاضی (کسر، توان، ضرب) به عبارتهای معتبر C++ با توجه به اولویت عملگرها
عبارت (Expression) چیست؟
تا اینجا یاد گرفتیم که مقداری را در یک متغیر ذخیره کنیم (int a = 10;) یا آن را چاپ کنیم (cout << a;). اما قدرت اصلی برنامهنویسی در محاسبه است؛ یعنی ترکیب چند متغیر و عدد برای تولید یک مقدار جدید.
به ترکیب مقادیر، متغیرها و عملگرها که در نهایت یک مقدار تولید میکند، عبارت (Expression) میگویند. مثلاً a + b * 2 یک عبارت است که ارزش آن پس از محاسبه به دست میآید. در این درس میآموزیم چطور عبارتهای ریاضی را در C++ بنویسیم، چه تلههایی در تقسیم نهفته است، و چگونه فرمولهای ریاضی کتاب درسی را به کد تبدیل کنیم.
مفهوم کلیدی: در C++ علامت = یک عملگر انتساب است که مقدار سمت راست را در متغیر سمت چپ قرار میدهد. بنابراین x = a + b; یعنی «مقدار a + b را محاسبه کن و در x بریز».
عملگر (Operator) در برابر عملوند (Operand)
وقتی مینویسیم a + b = c سه قسمت داریم:
a و b → عملوند (Operand): مقادیری که عملیات روی آنها انجام میشود (متغیرها، ثابتها یا عبارتهای دیگر).
+ → عملگر (Operator): نمادی که میگوید چه عملی روی عملوندها انجام شود.
= → عملگر انتساب (Assignment): مقدار سمت راست را در متغیر سمت چپ قرار میدهد.
ساختار کلی هر عبارت بهصورت operand1 OP operand2 است که در آن OP یک عملگر دودویی (Binary Operator) است. C++ انواع زیادی عملگر دارد: حسابی، رابطهای، منطقی، بیتی و... در این درس فقط پنج عملگر حسابی پایه را بررسی میکنیم: +، -، *، /، %.
پنج عملگر حسابی پایه
جدول کامل عملگرهای حسابی C++:
عملگر
نام
مثال
نتیجه
+
جمع (Addition)
7 + 3
10
-
تفریق (Subtraction)
7 - 3
4
*
ضرب (Multiplication)
7 * 3
21
/
تقسیم (Division)
7 / 2
3 (تقسیم صحیح!)
%
باقیمانده (Modulo)
7 % 2
1
نکتهی بسیار مهم: در C++ علامت × برای ضرب وجود ندارد؛ از * استفاده میکنیم. همچنین کسر a/b بهصورت a / b نوشته میشود. وقتی هر دو عملوند int باشند، نتیجه تقسیم صحیح است؛ یعنی قسمت اعشاری حذف میشود. این یکی از تلههای کلاسیک C++ است که در ادامه به طور کامل بررسیش میکنیم.
مثال ۱: چهار عملگر پایه روی دو عدد
این برنامه چهار عملگر اول را روی دو عدد صحیح اعمال میکند. به خروجی قسمت تقسیم دقت کنید: 7 / 2 خروجی 3 میدهد، نه 3.5! دلیل این رفتار را در بخش بعد توضیح میدهیم.
همچنین برای خوانایی بیشتر، قبل از هر مقدار یک برچسب متنی (مثل "a+b = ") چاپ میکنیم تا کاربر بداند هر خط چه چیزی را نشان میدهد.
برنامهای که a و b را گرفته و جمع، تفریق، ضرب و تقسیم آنها را چاپ میکندcpp
$خروجی برنامه
Enter two integers: 7 2
a + b = 9
a - b = 5
a * b = 14
a / b = 3
در حال باز کردن ویرایشگر…
قانون طلایی: تقسیم صحیح در برابر تقسیم اعشاری
قاعدهی مهم C++ که بسیاری از تازهکارها را گیر میاندازد:
اگر هر دو عملوند تقسیم از نوع int باشند، نتیجه نیز int است و قسمت اعشاری بدون گرد شدن حذف میشود (Truncation).
یعنی:
7 / 2 → 3 (نه ۳.۵ و نه ۴، مستقیم برش اعشار)
-7 / 2 → -3 (با علامت)
1 / 3 → 0
10 / 3 → 3
اما اگر حداقل یکی از دو عملوند از نوع اعشاری (float یا double) باشد، نتیجه اعشاری میشود:
7.0 / 2 → 3.5
7 / 2.0 → 3.5
7.0 / 2.0 → 3.5
این رفتار به نوع متغیرها بستگی دارد، نه به مقدار آنها. یعنی اگر int a = 7, b = 2; تعریف کنیم، a / b همچنان 3 میشود حتی اگر a مقدار ۷ داشته باشد. برای رفع این مشکل باید تبدیل نوع (Type Casting) انجام دهیم که در ادامه میآید.
مثال ۲: چهار حالت تقسیم صحیح و اعشاری
این چهار برنامه کوچک (که در نسخه اصلی جزوه کنار هم نوشته شده بودند) رفتار تقسیم را در حالتهای مختلف نشان میدهند. در هر حالت، نوع متغیرها تعیین میکند که خروجی 0، 0.5 یا عدد دیگری باشد.
حالت ۱: int / int → نتیجه int → 5 / 10 = 0 (تقسیم صحیح)
حالت ۲: int / float → نتیجه float → 5 / 10.0 = 0.5
حالت ۳: float / int → نتیجه float → 5.0 / 10 = 0.5
حالت ۴: ذخیره نتیجه اعشاری در متغیر int → اعشار بریده میشود → 0
همان مفهوم در چهار متغیر مختلف — خروجیها با دقت بررسی کنیدcpp
سه تله کلاسیک در تقسیم C++ که هر برنامهنویس تازهکاری دستکم یکبار در آن میافتد:
۱. تقسیم صحیح ناخواسته: اگر sum و n هر دو int باشند، sum / n قسمت اعشاری را حذف میکند. برای گرفتن میانگین واقعی:
main.cppcpp
۲. تقدم عملگرها: sum / n * 100 برابر است با (sum / n) * 100، نه sum / (n * 100). اگر میخواهید sum را بر حاصلضرب n*100 تقسیم کنید، باید پرانتز بگذارید.
۳. تقسیم بر صفر: اگر مقسومعلیه (طرف راست /) صفر باشد، برنامه با خطای زمان اجرا (Runtime Error) کرش میکند. همیشه قبل از تقسیم، شرط if (b != 0) بگذارید.
main.cppcpp
عملگر باقیمانده: `%`
عملگر % (Modulo) باقیماندهی تقسیم صحیح دو عدد را برمیگرداند. این عملگر فقط روی اعداد صحیح (int) کار میکند، نه اعشاری.
مثالها:
7 % 2 → 1 (چون ۷ = ۳×۲ + ۱)
10 % 3 → 1 (چون ۱۰ = ۳×۳ + ۱)
12 % 4 → 0 (چون ۱۲ دقیقاً بر ۴ بخشپذیر است)
100 % 10 → 0
528 % 10 → 8 (رقم یکان!)
چهار کاربرد اصلی % که امتحان میآید:
۱. استخراج رقم یکان: n % 10 رقم آخر یک عدد صحیح را میدهد.
۲. بررسی زوج/فرد: اگر n % 2 == 0 باشد، n زوج است؛ وگرنه فرد.
۳. بررسی بخشپذیری: n % 7 == 0 یعنی n مضرب ۷ است.
۴. چرخش ساعت: hour % 24 یا minute % 60.
هشدار: اگر عملوند سمت راست % صفر باشد، برنامه خطای زمان اجرا میدهد.
مثال ۳: استخراج ارقام با `/` و `%`
این یکی از پرکاربردترین الگوهای برنامهنویسی است: ترکیب / و % برای پیمایش ارقام یک عدد.
قاعدهی کلی برای عدد صحیح مثبت n:
n % 10 → رقم یگان
(n / 10) % 10 → رقم دهگان
(n / 100) % 10 → رقم صدگان
در مثال پایین، عدد 528:
528 / 10 → 52 (یک رقم حذف شد)
528 % 10 → 8 (رقم یکان)
از عدد ۵۲۸، رقم دهگان و یکان را جدا کنیدcpp
$خروجی برنامه
a / 10 = 52
a % 10 = 8
(a / 10) % 10 = 2
(a / 100) % 10 = 5
در حال باز کردن ویرایشگر…
تبدیل نوع (Type Casting): ضمنی و صریح
گاهی لازم است مقدار یک متغیر را به نوع دیگری تبدیل کنیم. این کار Type Casting نامیده میشود و دو نوع دارد:
۱. تبدیل ضمنی (Implicit Casting)
وقتی در یک عبارت، دو عملوند از نوعهای مختلف شرکت کنند، C++ خودش عملوند ضعیفتر را به نوع قویتر ارتقا میدهد. ترتیب قدرت: char < int < long < float < double.
مثلاً 5 + 2.5 در واقع 5.0 + 2.5 = 7.5 محاسبه میشود. این تبدیل خودکار است.
یک حالت خاص: وقتی یک مقدار float را در متغیر int میریزیم، قسمت اعشاری بدون گرد شدن حذف میشود:
main.cppcpp
۲. تبدیل صریح (Explicit Casting)
گاهی خودمان میخواهیم نوع را تغییر دهیم. سه روش معادل در C++ وجود دارد:
main.cppcpp
هر سه نتیجه یکسان میدهند؛ اما روش static_cast توصیه شده چون کامپایلر نوعها را دقیقتر بررسی میکند.
مثال ۴: تبدیل صریح برای تقسیم اعشاری
این یکی از مهمترین الگوهای C++ است: وقتی میخواهیم sum / n اعشاری باشد، حداقل یکی از دو طرف را به float یا double تبدیل میکنیم. سه روش معادل:
float(sum) / n
(float)sum / n
static_cast<float>(sum) / n
نکته: کافی است یکی از دو طرف تبدیل شود؛ C++ به طور خودکار طرف دیگر را هم به float ارتقا میدهد تا تقسیم اعشاری انجام شود.
محاسبه میانگین دو عدد صحیح بهصورت اعشاری با float(n)cpp
اصلاح: حساسیت به حروف بزرگ/کوچک (Float به جای float)
در صفحه ۱۰ جزوه، برنامهای نوشته شده بود که متغیرها را به اشتباه با Float (با F بزرگ) و F (با حرف بزرگ) تعریف کرده بود. در C++ زبان حساس به حالت (Case-Sensitive) است: float و Float دو چیز متفاوتاند. کلمه float یک کلمه کلیدی (Keyword) است که نوع داده اعشاری را تعریف میکند؛ اما Float هیچ معنایی ندارد و کامپایلر آن را بهعنوان یک نوع تعریفنشده میبیند و خطا میدهد.
همینطور F و f دو متغیر متفاوتاند. در نسخه اصلی جزوه، متغیر با f (کوچک) تعریف شده اما در ادامه با F (بزرگ) استفاده شده بود که باعث خطای کامپایل میشود.
نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاحشده و استاندارد
کد صحیحcpp
اولویت عملگرها (Operator Precedence)
وقتی چند عملگر در یک عبارت شرکت میکنند، C++ باید بداند کدام را اول محاسبه کند. این اولویت عملگرها (Precedence) نامیده میشود و از قوانین ریاضی پیروی میکند:
اولویت
عملگرها
توضیح
۱ (بالا)
()
پرانتز همیشه اول
۲
++، --، (type)، - (منفی یک طرفه)
عملگرهای یگانی
۳
*، /، %
ضرب و تقسیم همتراز
۴
+، -
جمع و تفریق
۵ (پایین)
=، +=، -=، ...
انتساب
قواعد مهم:
پرانتز همیشه اول محاسبه میشود. اگر شک دارید، پرانتز بگذارید!
عملگرهای همتراز (مثل * و /) از چپ به راست محاسبه میشوند. یعنی 8 / 2 * 3 برابر (8/2)*3 = 12 است، نه 8/(2*3) = 1.
عملگرهای انتساب از راست به چپ اجرا میشوند. یعنی a = b = 5 اول b = 5 را انجام میدهد و سپس a = b.
شکل postfix عملگرهای ++/-- (مثل a++) اولویت بالاتری از شکل prefix (مثل ++a) و سایر عملگرهای یگانی دارد؛ جدول بالا برای سادگی هر دو را در یک ردیف آورده است.
نکته عملی: در فرمولهای پیچیده همیشه پرانتز بگذارید تا هم کد خواناتر باشد و هم باگ پیش نیاید.
مثال ۵: ترجمه فرمول ریاضی به C++
ترجمه فرمولهای ریاضی به C++ نیاز به دقت در مورد سه چیز دارد: ضرب (* به جای ×)، تقسیم (کسر خط بالا به /) و توان (بهصورت ضرب مکرر یا با تابع pow).
قاعده مهم: هر کسر a / b در ریاضی به (a) / (b) تبدیل میشود؛ اگر مخرج حاصلضرب چند عبارت است، حتماً دور آن پرانتز بگذارید. مثلاً a / (b * c) نه a / b * c که اشتباه محاسبه میشود.
برای توان a^2 دو راه داریم:
a * a (ساده و سریع برای توانهای صحیح کوچک)
pow(a, 2) (نیازمند <cmath> و مناسب توان اعشاری)
چگونه کسر و توان را به کد تبدیل کنیمcpp
$خروجی برنامه
Enter a, b, c, d: 3 4 1 2
(ab-cd)/2 + 2ad = 17
Enter x, y, z: 2 3 1
(a^2-b^2)/(2x^2y^2) - 4z^2/3 = -1.430556
در حال باز کردن ویرایشگر…
اصلاح: ترجمه نادرست فرمول در جزوه
در صفحه ۹ جزوه، فرمول (a^2 - b^2) / (2x^2 y^2) - 4z^2 / 3 بهصورت (a*a-b*b)/2*x*x*y*y - 4/3*x*x ترجمه شده بود که سه باگ جدی دارد:
۱. باگ اولویت (Precedence): نوشتن /2*x*x*y*y معادل ((a*a-b*b)/2)*x*x*y*y است، نه (a*a-b*b)/(2*x*x*y*y). چون / و * همترازند و از چپ به راست اجرا میشوند. باید مخرج را در پرانتز بگذاریم: / (2*x*x*y*y).
۲. باگ تقسیم صحیح: 4/3 بین دو عدد صحیح، برابر 1 میشود (تقسیم صحیح)، نه 1.333. باید 4.0/3.0 بنویسیم.
۳. باگ متغیر: در فرمول اصلی 4z^2 آمده، اما در ترجمه x*x نوشته شده. متغیر اشتباه!
نسخه اشتباه جزوه
کد دارای باگcpp
نسخه اصلاحشده و استاندارد
کد صحیحcpp
فلوچارت: خواندن دو عدد، محاسبه و چاپ نتیجه
این الگوریتم پایه برای هر برنامه محاسباتی: دریافت دو عدد، انجام چهار عمل اصلی، چاپ نتایج. این الگو را در بسیاری از مسائل پایه (مساحت مستطیل، محیط، میانگین و...) خواهید دید.
نام درس، موضوع یا کلمه کلیدی را بنویسید و با Enter به آن بروید
1#include<iostream>2usingnamespace std;34intmain(){5int a, b;6 cout <<"Enter two integers: ";7 cin >> a >> b;89 cout <<"a + b = "<< a + b << endl;10 cout <<"a - b = "<< a - b << endl;11 cout <<"a * b = "<< a * b << endl;12 cout <<"a / b = "<< a / b << endl;// تقسیم صحیح!1314return0;15}
1#include<iostream>2usingnamespace std;34intmain(){5// حالت ۱: هر دو int6int a1 =5, b1 =10;7float f1 = a1 / b1;// 5/10 = 0 (تقسیم صحیح)8 cout <<"int/int = "<< f1 << endl;910// حالت ۲: a از نوع int، b از نوع float11int a2 =5;12float b2 =10;13float f2 = a2 / b2;// 5/10.0 = 0.514 cout <<"int/float = "<< f2 << endl;1516// حالت ۳: هر دو float17float a3 =5, b3 =10;18float f3 = a3 / b3;// 5.0/10.0 = 0.519 cout <<"float/float= "<< f3 << endl;2021// حالت ۴: نتیجه اعشاری در int ذخیره میشود22float a4 =5, b4 =10;23int f4 = a4 / b4;// 0.5 → 0 (برش اعشار)24 cout <<"int= float = "<< f4 << endl;2526return0;27}
cout <<(float)sum / n;// یا float(sum)/n یا sum * 1.0 / n
if(b !=0){ cout << a / b;}else{ cout <<"Error: division by zero";}
float f =2.8;int x = f;// x = 2 (اعشار بریده میشود)
int n =7;float a =float(n);// روش تابعی (C++)float b =(float)n;// روش سبک Cfloat c =static_cast<float>(n);// روش مدرن و امن C++
1#include<iostream>2usingnamespace std;34intmain(){5int sum =55;6int n =3;78// بدون cast: تقسیم صحیح9 cout <<"Without cast: "<< sum / n << endl;// 181011// با cast صریح: تقسیم اعشاری12 cout <<"float(sum)/n : "<<float(sum)/ n << endl;// 18.333313 cout <<"(float)sum/n : "<<(float)sum / n << endl;// 18.333314 cout <<"sum*1.0/n : "<< sum *1.0/ n << endl;// 18.33331516// تبدیل float به int: اعشار بریده میشود (نه گرد!)17float f =2.8;18int x =int(f);// x = 219 cout <<"int(2.8) = "<< x << endl;2021return0;22}
1#include<iostream>2usingnamespace std;34main()5{6 Float a =5, b =10, f;// خطا: Float تعریف نشده (باید float)7 F = a / b;// خطا: F تعریف نشده (باید f)8 cout << F;// خطا: F تعریف نشده9}
1#include<iostream>2usingnamespace std;34intmain(){5float a =5, b =10, f;// float با حروف کوچک6 f = a / b;// f با حرف کوچک7 cout << f << endl;// خروجی: 0.58return0;9}
1#include<iostream>2usingnamespace std;34intmain(){5int a, b, c, d;6 cout <<"Enter a, b, c, d: ";7 cin >> a >> b >> c >> d;89// فرمول 1: (ab - cd) / 2 + 2ad10int r1 =(a * b - c * d)/2+2* a * d;11 cout <<"(ab-cd)/2 + 2ad = "<< r1 << endl;1213// فرمول 2: (a^2 - b^2) / (2 * x^2 * y^2) - (4 * z^2) / 314// این فرمول اعشاری است، پس از double استفاده میکنیم15double x, y, z;16 cout <<"Enter x, y, z: ";17 cin >> x >> y >> z;18double r2 =(a * a - b * b)/(2.0* x * x * y * y)19-(4.0* z * z)/3.0;20 cout <<"(a^2-b^2)/(2x^2y^2) - 4z^2/3 = "<< r2 << endl;2122return0;23}
1// فرمول صحیح: (a^2-b^2) / (2x^2y^2) - 4z^2 / 32int r =(a*a - b*b)/2*x*x*y*y -4/3*x*x;3// باگها:4// 1) /2*x*x*y*y اولویت اشتباه، باید /(2*x*x*y*y)5// 2) 4/3 تقسیم صحیح = 1، باید 4.0/3.06// 3) x*x به جای z*z در جمله دوم7// 4) متغیرها باید double باشند چون فرمول اعشاری است
1#include<iostream>2usingnamespace std;34intmain(){5double a, b, x, y, z;6 cin >> a >> b >> x >> y >> z;7double r =(a*a - b*b)/(2.0* x*x * y*y)8-(4.0* z*z)/3.0;9 cout << r << endl;10return0;11}
flow.svg100%
Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.