شیوه استفاده از عملگر Modulo در PHP — به زبان ساده
زبان برنامهنویسی PHP به طور کلی هشت عملگر حسابی دارد. رایجترین موارد این عملگرها شامل عملگر «جمع» (+)، «تفریق» (-)، «ضرب» (*) و «تقسیم» (/) هستند. با این حال یک عملگر کمتر شناخته به نام عملگر پیمانهای یا Modulo با نماد (%) نیز وجود دارد. در این راهنما به توضیح کارکرد این عملگر میپردازیم و برخی از مثالهای کاربردی آن را مورد بررسی قرار میدهیم.
عملگر Modulo چه وظیفهای دارد؟
اگر دو متغیر به نامهای a$ و b$ داشته باشیم و بخواهیم مقدار «a % $b$» (غالباً به صوت a به پیمانه b خوانده میشود) را محاسبه کنیم، عملگر Modulo باقیمانده تقسیم a$ بر b$ را ارائه میکند. Modulo یک عملگر صحیح (Integer) است و از این رو هر دو عملوند خود را نیز پیش از محاسبه باقیمانده، به اعداد صحیح تبدیل میکند. از این رو اساساً Modulo به عمل تقسیم صحیح میپردازد و سپس هر آن چه از تقسیم باقیمانده است را بازگشت میدهد.
علامت مقدار بازگشتی از عملیات Modulo به وسیله علامت مقدار «خارجقسمت» تعیین میشود. در تقسیم، نتیجه تقسیم دو عدد منفی یک عدد مثبت خواهد بود. با این وجود، این موضوع در مورد عملگر Modulo صدق نمیکند. علامت مقسوم تأثیری بر مقدار نهایی ندارد. به چند مثال زیر توجه کنید:
1<?php
2
3echo 1089 % 37;
4// Output: 16
5
6echo 1089 % -37;
7// Output: 16
8
9echo -1089 % 37;
10// Output: -16
11
12echo -1089 % -37;
13// Output: -16
14
15echo -55.4 % -4.2;
16// Output: -3
17
18echo -55.9 % -4.8;
19// Output: -3
20
21echo -55 % -4;
22// Output: -3
23
24?>
پیمانه اعشاری
اگر میخواهید باقیمانده تقسیم دو عدد اعشاری را پیدا کنید باید از تابع (fmod($dividend، $divisor استفاده کنید. این تابع مقدار اعشاری باقیمانده را پس از انجام تقسیم بازگشت میدهد. مقدار باقیمانده همان علامت مقسوم را خواهد داشت و بزرگی آن کمتر از مقسومعلیه خواهد بود. رابطه بین این سه عدد به صورت زیر است:
1$dividend = i*$divisor + $remainder
در اینجا مقدار i همواره یک عدد صحیح است.
باید به خاطر داشته باشید که محاسبه اعداد اعشاری به دلیل محدودیتهای بازنمایی اعداد کسری به صورت دودویی یا دهدهی همواره دقت بالایی ندارد. برای نمونه کسر نمیتواند به شکل اعشاری دقیق بازنمایی شود. ما نمیتوانیم تا ابد اعداد را به صورت ...0.33333 بنویسیم و این کار را باید در جایی بالاخره متوقف کنیم. با هر رقم 3 که به عدد فوق اضافه کنیم به بازنمایی اعشاری دقیق عدد نزدیکتر میشویم؛ اما در هر حال آن عدد بازنمایی دقیق عدد نخواهد بود.
این نوع عدم دقت موجب بروز مشکلاتی هنگام استفاده از تابع ()fmod میشود و نتایج به طور کلی قابل اعتماد نیستند. در ادامه مثالی از تابع ()fmod ارائه کردهایم:
1<?php
2
3echo fmod(18.8, 2);
4// Output: 0.8
5
6echo fmod(18.8, 0.2);
7// Output: 0.2
8
9?>
مقدار دوم دقیق نیست، زیرا 18.8 تقسیم بر 0.2 باقیماندهای ندارد. این یک نقص محاسبه اعداد اعشاری از سوی رایانهها است.
کاربردهای عملگر Modulo
در این راهنما خود را به پیمانه اعداد صحیح محدود کردهایم، چون رایجتر است و کاربردهای بیشتری دارد.
بررسی این که آیا عددی مضرب عدد دیگر است؟
در صورتی که نتیجه عملگر Modulo صفر باشد، نشان میدهد که عدد نخست، به طور کامل از سوی عدد دوم تقسیمپذیر است. این وضعیت در مواردی که میخواهیم بررسی کنیم آیا یک عدد مضربی از عدد دیگر است یا نه، مفید خواهد بود. احتمالاً رایجترین کاربرد این مشخصه در عملگر Modulo برای بررسی زوج یا فرد بودن یک عدد است. مثالی از آن را در ادامه ملاحظه میکنید:
1?php
2
3$colors = ['violet', 'indigo', 'blue', 'green', 'yellow', 'orange', 'red'];
4$color_count = count($colors);
5
6if($color_count % 2 == 0) {
7 echo 'We have created some color pairs for you.';
8} else {
9 echo 'Please specify one more or one less color to make pairing possible.';
10}
11
12?>
در مثال فوق، میتوانید فهرستی از رنگها را از یک کاربر بگیرید و از وی بخواهید تا تعداد زوجی از رنگها را بازگشت دهد.
در مثال زیر از استدلال مشابهی برای ایجاد گروههایی از دانشجویان استفاده کردهایم که هر یک 5 عضو دارند. در زندگی واقعی، باید از کد بیشتری برای گروهبندی دانشجویان استفاده کنید؛ اما ایده اساسی این است که بررسی کنید آیا تعداد کل دانشجویان مضربی از 5 است یا نه.
1<?php
2
3$total_students = 25;
4
5if($total_students % 5 == 0) {
6 echo 'Each group of five students has been given an assignment.';
7} else {
8 echo 'Sorry, it is impossible to create groups of five students right now. Please get more students.';
9}
10
11?>
تغییر دادن اعداد برای اینکه مضربی از عدد دیگر باشند
در بخش فوق از عملگر Modulo استفاده کردهایم تا به اطلاع کاربران برسانیم که صرفاً مقادیر ورودی را در مضربهای مشخصی ارائه کنند. اگر این کار ممکن نباشد، میتوانیم این الزام را ایجاد کنیم که ورودی زوج باشد و مضربی از 5 یا عدد دیگر نیز باشد.
عملگر Modulo بخش صحیح عدد باقیمانده پس از تقسیم کردن عدد نخست بر عدد دوم را ارائه میکند. این بدان معنی است که تفریق کردن باقیمانده از عدد نخست موجب میشود که مضربی از عدد دوم باشد. برای مثال، 28 را میتوان با محاسبه 28%5 طوری تغییر داد که مضربی از 5 باشد. در این حالت، مقدار پیمانه یا Modulo برابر با 3 خواهد بود. اینک میتوانیم 3 را از عدد اصلی کم کنیم تا به مضربی از 5 تبدیل شود. در کد زیر الزام میشود که همه اعداد مثبت x با کسر مقدار متناسبی، به مضربی از عدد مثبت y دیگر تبدیل شوند:
1x = x - (x % y)
در مثال قبلی در مورد 28 دانشجو میتوانیم 3 دانشجو را حذف کنیم و گروههایی پنج نفره از دانشجویان باقیمانده تشکیل دهیم.
1<?php
2
3$total_students = 28;
4
5if($total_students % 5 == 0) {
6 echo 'Each group of five students has been given an assignment.';
7} else {
8 $removed_students = $total_students % 5;
9 $total_students -= $removed_students;
10 echo 'We have created groups of five students by removing the last '.$removed_students.' students from the list.';
11}
12
13?>
قرار دادن محدودیت روی ورودی
همان طور که در ابتدای این نوشته اشاره کردیم، در مورد اعداد مثبت، عملگر Modulo یک عدد بین 0 و N-1 بازگشت میدهد که N مقسومعلیه است. این بدان معنی است که میتوانید برای هر ورودی نوعی سقف تعریف کنید تا برخی عملیات را به طور مکرر و متوالی اجرا کند. در ادامه مثالی از این وضعیت را ملاحظه میکنید:
1<?php
2
3$colors = ['violet', 'indigo', 'blue', 'green', 'yellow'];
4
5$color_count = count($colors);
6$total_images = 180;
7$background_color = '';
8
9for($i = 0; $i < $total_images; $i++) {
10 $background_color = $colors[$i % $color_count];
11 echo "Setting image background color to $background_color.";
12}
13
14?>
در مثال فوق، ما تنها پنج رنگ داریم؛ اما در مجموع 180 تصویر وجود دارد. این بدان معنی است که باید به طور مکرر روی آن پنج رنگ حلقهای تعریف کنیم و آنها را به همه تصاویر موجود انتساب دهیم. عملگر modulo این نیاز را به خوبی برآورده میکند. این عملگر مقدار i % $color_count$ را بین 0 و (1-5) یا 4 رنگ موجود منحصر میکند. به بیان دیگر ما میتوانیم همه رنگهای آرایه خود را به طور متوالی به سادگی انتخاب کنیم.
انجام کارهایی در N-اُمین دفعه اجرای یک حلقه
زمانی که یک حلقه را پیمایش میکنیم، میتوانیم مقدار متغیر افزایشی را در هر بار اجرای حلقه بررسی کرده و یک وظیفه خاص را پس از N-اُمین اجرای آن انجام دهیم. یکی از موارد کاربرد عملی این وضعیت اطلاعرسانی به کاربران در مورد فرایندی است که اجرای آن مدت زیادی طول میکشد. فرض کنید قرار است با استفاده از PHP روی 1000 تصویر متفاوت تغییراتی اجرا کنیم. اگر این تغییرات، بزرگ باشند، زمان مورد نیاز برای بهروزرسانی همه تصاویر قابل توجه خواهد بود.
در چنین مواردی، کاربران هیچ راهی برای دانستن این که آیا برنامه از کار افتاده است یا در پسزمینه، مشغول کار است نخواهند داشت. در این موارد باید روند پیشرفت کار را پس از ویرایش مثلاً هر 10 تصویر به کاربر اطلاع دهیم.
1<?php
2
3$total_images = 1000;
4
5for($i = 1; $i <= $total_images; $i++) {
6 update_images($image_resource);
7 if($i % 10 == 0) {
8 $percent = $i*100/$total_images;
9 echo 'Already processed '.$percent.'% images.';
10 }
11}
12
13?>
تابع ()update_images در مثال فوق کاملاً ساختگی است؛ اما میتوان آن را با هر پردازش دیگری مانند تغییر اندازه تصاویر، افزودن واترمارک، خاکستری کردن تصاویر و موارد دیگر جایگزین کرد. برای مطالعه مطالب بیشتر در این خصوص میتوانید از مطلب «رندر کردن اشکال هندسی و متن روی تصاویر با PHP» و «تغییر اندازه و دستکاری تصاویر در PHP» استفاده کنید.
تبدیل بین واحدهای اندازهگیری مختلف
عملگر Modulo میتواند برای تبدیل بین واحدهای مختلف اندازهگیری نیز استفاده شود. برای نمونه میتوانید از آن استفاده کنید و زمانی را که به صورت ثانیه بیان شده است، به صورت ساعت، دقیقه و ثانیه بیان کنید. به طور مشابه میتوانید مسافتی که بر اساس سانتیمتر بیان شده را به کیلومتر، متر و سانتیمتر تبدیل کنید. در ادامه مثالی از این وضعیت را ملاحظه میکنید:
1<?php
2
3$total_seconds = 32987;
4
5$hours = (int)($total_seconds / 3600);
6$minutes = (int)(($total_seconds - 3600 * $hours )/60);
7$seconds = $total_seconds % 60;
8
9echo 'Hours:'.$hours.' Minutes:'.$minutes.' Seconds:'.$seconds.'';
10
11?>
در کد فوق، ما کار خود را با تقسیم کردن تعداد کل ثانیهها بر 3600 و تبدیل قالب (Cast) آن به یک عدد صحیح آغاز میکنیم. بدین ترتیب تعداد کل ساعتها به دست میآید، زیرا هر ساعت 3600 ثانیه است.
در مرحله بعدی، مقدار زیر را از عدد اصلی ثانیهها کسر میکنیم:
3600 * $hours
بدین ترتیب ثانیههایی که به ساعت تبدیل شدهاند از مقدار کلی کم میشود. سپس با تقسیم مقدار باقیمانده بر 60 تعداد کل دقیقهها به دست میآید. در نهایت از عملگر Modulo برای دریافت کل ثانیههای باقیمانده استفاده میشود.
سخن پایانی
همان طور که در این مقاله دیدیم، عملگر Modulo با این که عملگر سادهای به نظر میرسد؛ اما کاربردهای زیادی دارد. این راهنما را با بررسی عملگر Modulo برای اعداد مثبت و منفی و همچنین اعشاری آغاز کردیم. پس از آن برخی موارد استفاده متداول از این عملگر را مورد بررسی قرار دادیم و در نهایت کاربرد آن در تبدیل مقیاس اندازهگیری را نشان دادیم.
اگر این مطلب برای شما مفید بوده است، آموزشهای زیر نیز به شما پیشنهاد میشوند:
- مجموعه آموزش های برنامه نویسی PHP
- مجموعه آموزش های برنامه نویسی
- گنجینه برنامه نویسی PHP
- آموزش فریمورک لاراول PHP Laravel برای ساخت فروشگاه اینترنتی
- آموزش پروژه محور PHP — مجموعه مقالات جامع وبلاگ فرادرس
- محاسبات ریاضی با تابع های داخلی PHP — به زبان ساده
- برنامهنویسی PHP و هر آنچه برای شروع باید بدانید — آموزش جامع
==