درس ۴ از ۴۹ · آغاز راه

عملگرها

عملگرها روی مقدارها کار می‌کنند: حساب می‌کنند، مقایسه می‌کنند و شرط‌ها را به هم وصل می‌کنند. بیشترشان همان‌طور رفتار می‌کنند که انتظار دارید؛ این درس بیشتر به چند جایی می‌پردازد که این‌طور نیست.

حساب

+ - * / % مثل ریاضی کار می‌کنند و ** توان است. ضرب و تقسیم پیش از جمع و تفریق انجام می‌شوند و پرانتز ترتیب را عوض می‌کند.

ops-arith.salam
تابع ریشه:
    الف := ۱۷
    ب := ۵
    سرچاپ الف + ب, الف - ب, الف * ب, الف / ب, الف % ب
    سرچاپ ۲ ** ۱۰
    سرچاپ (۲ + ۳) * ۴, ۲ + ۳ * ۴
پایان
خروجی22 12 85 3 2 1024 20 14

+ رشته‌ها را هم به هم می‌چسباند و اگر سمت چپش رشته باشد، عدد را به متن تبدیل می‌کند: "جمع: " + ۵ می‌شود "جمع: 5". ادامه‌اش در درس رشته‌ها آمده است.

تقسیم و باقی‌مانده

تقسیم دو عدد صحیح، عدد صحیح می‌دهد: ۱۷ / ۵ می‌شود ۳ و % باقی‌مانده را می‌دهد، یعنی ۲. این دو با هم دقیقاً همان چیزی‌اند که برای تبدیل دقیقه به ساعت، شمردن تعداد میز لازم برای مهمان‌ها یا جدا کردن عدد زوج از فرد لازم دارید.

ops-divide.salam
تابع ریشه:
    دقیقه‌ها := ۱۳۵
    سرچاپ دقیقه‌ها / ۶۰، "ساعت و"، دقیقه‌ها % ۶۰، "دقیقه"
    مهمان‌ها := ۱۷
    صندلی میز := ۴
    میزها := (مهمان‌ها + صندلی میز - ۱) / صندلی میز
    سرچاپ "میز لازم:"، میزها
    سرچاپ "صندلی خالی:"، میزها * صندلی میز - مهمان‌ها
    ن := ۷
    سرچاپ ن، "عددی"، ن % ۲ == ۰ ? "زوج" : "فرد"، "است"
    سرچاپ -۷ / ۲، -۷ % ۲
پایان
خروجی2 ساعت و 15 دقیقه میز لازم: 5 صندلی خالی: 3 7 عددی فرد است -3 -1

دو نکته را به خاطر بسپارید:

  • تقسیم به سمت صفر بریده می‌شود، پس -۷ / ۲ می‌شود -3، و باقی‌مانده علامت عدد سمت چپ را می‌گیرد، پس -۷ % ۲ می‌شود -1. به همین دلیل شرط ن % ۲ == ۱ عددهای فرد منفی را نمی‌گیرد، اما ن % ۲ != ۰ همه را می‌گیرد.
  • % فقط روی عدد صحیح کار می‌کند و روی عدد اعشاری خطای ترجمه می‌دهد. تقسیم بر صفری که مستقیم در کد نوشته شده هم خطای ترجمه است، اما صفری که هنگام اجرا پیدا شود بررسی نمی‌شود و ممکن است برنامه را از کار بیندازد؛ پس پیش از تقسیم، مقسوم‌علیه را بررسی کنید.

توان

** عدد را به توان می‌رساند و نتیجه‌اش همیشه اعشار۶۴ است، حتی برای دو عدد صحیح. به همین دلیل ۲ ** ۰.۵ و ۲ ** -۱ هم کار می‌کنند، اما اگر عدد صحیح لازم دارید باید با برگردان صحیح تبدیلش کنید.

ops-power.salam
تابع ریشه:
    باکتری‌ها := ۱۰۰ * ۲ ** ۱۰
    سرچاپ "پس از ده بار دوبرابر شدن:"، باکتری‌ها
    سرچاپ ۲ ** ۰.۵، ۲ ** -۱
    سرچاپ ۲ ** ۳ ** ۲، -۲ ** ۲، (-۲) ** ۲
    خانه‌ها := (۲ ** ۱۰) برگردان صحیح
    سرچاپ خانه‌ها / ۳
پایان
خروجیپس از ده بار دوبرابر شدن: 102400 1.4142135623730951 0.5 512 -4 4 341

** از راست گروه‌بندی می‌شود، پس ۲ ** ۳ ** ۲ همان ۲ ** ۹ است، و از منفیِ پیش از عدد قوی‌تر است، پس -۲ ** ۲ مثل ریاضی می‌شود -4. به همین دلیل **= روی متغیر اعشار۶۴ کار می‌کند اما روی متغیر صحیح نه، چون نتیجه دوباره در آن جا نمی‌شود.

مقایسه

مقایسه‌ها مقدار منطقی می‌دهند. به‌جای ==، !=، <، >، <= و >= می‌توانید برابر، نابرابر، کوچکتر، بزرگتر، کوچکتربرابر و بزرگتربرابر بنویسید (دو تای آخر با فاصله هم نوشته می‌شوند: کوچکتر برابر). شرط‌ها را با و و یا به هم وصل کنید و با وارونه برعکس کنید.

ops-compare.salam
تابع ریشه:
    سن := ۲۰
    سرچاپ سن > ۱۸, سن < ۱۸, سن == ۲۰, سن != ۲۰
    سرچاپ سن برابر ۲۰, سن نابرابر ۳۰
    سرچاپ سن بزرگتر ۱۸, سن کوچکتربرابر ۲۰
    سرچاپ سن >= ۱۸ و سن <= ۶۰
    سرچاپ سن < ۱۰ یا سن > ۱۵
    سرچاپ وارونه (سن > ۱۸)
    سرچاپ "انار" < "سیب"، "سیب" == "سیب"
پایان
خروجیtrue false true false true true true true true true false true true

رشته‌ها هم با همین عملگرها مقایسه می‌شوند. == یکسان بودن متن را می‌سنجد و < بر پایه‌ی کد نویسه‌ها مرتب می‌کند. این ترتیب برای الفبای انگلیسی درست است، اما حرف‌هایی مثل «پ»، «چ»، «ژ»، «ک»، «گ» و «ی» در یونیکد پس از حرف‌های عربی آمده‌اند. برای همین "گل" < "لاله" نادرست است، با این‌که در الفبا «گ» پیش از «ل» می‌آید؛ برای مرتب‌سازی الفبایی فارسی به این ترتیب تکیه نکنید.

مقایسه‌ها زنجیر نمی‌شوند. ۱ < ع < ۱۰ مقدار منطقی ۱ < ع را با ۱۰ مقایسه می‌کند و مترجم آن را نمی‌پذیرد؛ بنویسید ع > ۱ و ع < ۱۰.

ترکیب شرط‌ها

و و یا به محض این‌که جواب معلوم شود می‌ایستند. اگر سمت چپ و نادرست باشد، سمت راستش اصلاً اجرا نمی‌شود؛ اگر سمت چپ یا درست باشد هم همین‌طور. به این ترتیب می‌توانید یک بررسی پرخطر را پشت یک بررسی ساده پناه دهید، همان کاری که نخستین اگر این نمونه می‌کند: تقسیم فقط وقتی انجام می‌شود که تعداد صفر نباشد.

ops-logic.salam
تابع بررسی(نام: رشته): منطقی:
    سرچاپ "  بررسی شد"، نام
    برگشت درست
پایان

تابع ریشه:
    تعداد := ۰
    جمع := ۵۰
    اگر تعداد > ۰ و جمع / تعداد > ۱۰:
        سرچاپ "میانگین بالاست"
    وگرنه:
        سرچاپ "هنوز داده‌ای نیست"
    پایان
    سرچاپ نادرست و بررسی("الف")
    سرچاپ درست یا بررسی("ب")
    سرچاپ درست و بررسی("پ")
    وارد شده := درست
    مسدود := نادرست
    سرچاپ "اجازه‌ی ارسال:"، وارد شده و وارونه مسدود
پایان
خروجیهنوز داده‌ای نیست false true بررسی شد پ true اجازه‌ی ارسال: true

فقط فراخوانی سوم بررسی اجرا شد. وارونه از هر مقایسه‌ای قوی‌تر است، پس وارونه تعداد == ۳ یعنی (وارونه تعداد) == ۳ و خطا می‌دهد؛ بنویسید وارونه (تعداد == ۳) یا ساده‌تر تعداد != ۳. در سلام &&، || و ! وجود ندارند؛ مترجم آن‌ها را نمی‌پذیرد و واژه‌ی درست را پیشنهاد می‌کند.

عملگر سه‌تایی

شرط ? الف : ب اگر شرط درست باشد الف و گرنه ب را می‌دهد. به‌جای ? علامت سؤال فارسی ؟ هم پذیرفته می‌شود. سه‌تایی‌ها را می‌توان پشت هم گذاشت تا از میان چند بازه یکی انتخاب شود؛ از بالا به پایین خوانده می‌شوند و نخستین شرط درست برنده است.

ops-ternary.salam
تابع ریشه:
    دما := ۳۲
    هوا := دما > ۳۰ ? "گرم" : "معتدل"
    سرچاپ "هوا", هوا, "است"
    نمره := ۱۴
    رتبه := نمره >= ۱۷ ? "عالی" : نمره >= ۱۴ ? "خوب" : نمره >= ۱۰ ? "قبول" : "مردود"
    سرچاپ "نتیجه:"، رتبه
    موجودی := ۰
    سرچاپ موجودی > ۰ ؟ "موجود است" : "ناموجود"
پایان
خروجیهوا گرم است نتیجه: خوب ناموجود

هر دو شاخه باید هم‌گونه باشند: ن > ۳ ? "بزرگ" : ۰ خطاست. زنجیره‌ای با بیش از سه یا چهار حالت معمولاً با همخوان خواناتر است.

تغییر متغیر در جا

+=، -=، *=، /= و %= عملگر را اجرا می‌کنند و نتیجه را دوباره در همان متغیر می‌گذارند؛ پس متغیر باید ناپایا باشد. += به رشته هم چیزی می‌افزاید. ++ یکی اضافه و -- یکی کم می‌کند و تنها راه یکی زیاد یا کم کردن یک عدد هستند.

ops-compound.salam
تابع ریشه:
    ناپایا موجودی := ۱۰۰
    موجودی += ۵۰
    موجودی -= ۳۰
    موجودی *= ۲
    موجودی /= ۳
    موجودی %= ۵۰
    سرچاپ "موجودی:"، موجودی
    ناپایا گزارش := "آغاز"
    گزارش += "، ذخیره شد"
    گزارش += "، پرونده‌ها: " + ۳
    سرچاپ گزارش
    ناپایا ش := ۵
    ش++
    ش--
    ش++
    ق := ش++
    سرچاپ "ق:"، ق، "ش:"، ش
پایان
خروجیموجودی: 30 آغاز، ذخیره شد، پرونده‌ها: 3 ق: 6 ش: 7

این راه درست تغییر یک متغیر است و کامپایلر آن را اجبار می‌کند (خطای E162). برای یکی اضافه یا کم کردن بنویسید ن++ یا ن--؛ ن += ۱ و ن = ن + ۱ و ن = ۱ + ن همه رد می‌شوند. برای مقدارهای دیگر همان شکل ترکیبی را نگه دارید: به جای ن = ن + ۵ بنویسید ن += ۵ و به جای جمع = جمع * نرخ بنویسید جمع *= نرخ. دستورهایی که چیزی را عوض نمی‌کنند، مانند ن = ن یا ن += ۰ یا ن *= ۱، هم رد می‌شوند و پیام می‌گوید آن‌ها را بردارید. ن = دیگری - ن و ن = ن * الف + ب به‌روزرسانی خودِ متغیر نیستند و مجازند.

اگر ش++ به‌عنوان مقدار به کار رود، مقدار قدیمی را می‌دهد و بعد یکی اضافه می‌کند؛ برای همین ق برابر ۶ است و ش به ۷ می‌رسد. ++ش اول اضافه می‌کند. کد وقتی خواناتر است که ++ و -- در خط جداگانه‌ی خودشان بیایند.

عملگرهای بیتی

&، |، ^، ~ و جابه‌جایی‌های << و >> روی بیت‌های اعداد صحیح کار می‌کنند.

ops-bitwise.salam
تابع ریشه:
    الف := 0b1100
    ب := 0b1010
    سرچاپ الف & ب, الف | ب, الف ^ ب
    سرچاپ ۱ << ۴, ۲۵۶ >> ۲, ~۰
پایان
خروجی8 14 6 16 64 -1

کاربرد روزمره‌ی آن‌ها چند گزینه‌ی بله یا نه است که در یک عدد جا می‌گیرند و هر گزینه یک بیت است. |= گزینه را روشن می‌کند، &= ~ خاموشش می‌کند و & آن را می‌آزماید. جابه‌جایی ۱۰ بیت به راست همان تقسیم بر ۱۰۲۴ است.

ops-flags.salam
پایا خواندنی := ۱
پایا نوشتنی := ۲
پایا اجرایی := ۴

تابع ریشه:
    ناپایا مجوز := خواندنی | نوشتنی
    سرچاپ "نوشتن مجاز است:"، (مجوز & نوشتنی) != ۰
    مجوز |= اجرایی
    مجوز &= ~نوشتنی
    سرچاپ "نوشتن مجاز است:"، (مجوز & نوشتنی) != ۰
    سرچاپ "اجرا مجاز است:"، (مجوز & اجرایی) != ۰
    سرچاپ "بیت‌ها:"، مجوز
    سرچاپ "۵۰۰۰ بایت به کیلوبایت:"، ۵۰۰۰ >> ۱۰
پایان
خروجینوشتن مجاز است: true نوشتن مجاز است: false اجرا مجاز است: true بیت‌ها: 5 ۵۰۰۰ بایت به کیلوبایت: 4

پرانتزهای (مجوز & نوشتنی) != ۰ را نگه دارید. مثل زبان C، & از == و != ضعیف‌تر است و بدون پرانتز اول مقایسه انجام می‌شود. مترجم این یکی را می‌گیرد، چون آن‌وقت یک طرف & مقدار منطقی است. عملگرهای بیتی فقط عدد صحیح می‌پذیرند.

ترتیب اجرای عملگرها

از قوی‌ترین به ضعیف‌ترین. عملگرهای یک ردیف از چپ به راست اجرا می‌شوند، جز **.

عملگرهانمونه
برگردانع / ۲ برگردان اعشار۶۴ فقط ۲ را تبدیل می‌کند
** (از راست به چپ)۲ ** ۳ ** ۲ می‌شود ۵۱۲
- یک‌عملوندی، ~، وارونه-۲ ** ۲ می‌شود -4
*، /، %۲ + ۳ * ۴ می‌شود ۱۴
+، -۱ << ۴ + ۱ می‌شود ۳۲
<<، >>۱ << ۲ < ۵ درست است
<، <=، >، >= و واژه‌هایشان
==، !=، برابر، نابرابر
&، سپس ^، سپس |۶ & ۳ | ۸ می‌شود ۱۰
و
یادرست یا درست و نادرست درست است
? :شرط ? ۱ : ۲ + ۱۰ یا ۱ است یا ۱۲

هر وقت برای فهمیدن ترتیب مکث کردید، پرانتز بگذارید. هزینه‌ای ندارد و خواننده‌ی بعدی هم لازم نیست مکث کند.

دو علامت جمع یا تفریق پشت‌سرهم (مثل الف - -ب) خطاست؛ بنویسید الف + ب یا عبارت درونی را در پرانتز بگذارید: الف - (-ب). گونه‌هایی که خودتان می‌سازید می‌توانند معنای این عملگرها را تعیین کنند؛ درس گونه‌های تازه را ببینید.