🔀 کنترل جریان

عدد اول با حلقه؛ از کند تا سریع

۵ گام

یک مسئلهٔ واقعی، از «کار می‌کند» تا «خوب کار می‌کند»

عدد اول عددی بزرگ‌تر از ۱ است که فقط بر ۱ و خودش بخش‌پذیر باشد: ۲، ۳، ۵، ۷، ۱۱، … برای تشخیصش کافی است همهٔ اعداد ۲ تا n-1 را امتحان کنیم و ببینیم کدام n را می‌شمارند:

n = int(input())
divisors = 0
for i in range(2, n):
    if n % i == 0:
        divisors += 1

if divisors == 0:
    print("اول است")
else:
    print("اول نیست")

درست کار می‌کند، ولی بی‌دلیل زیاد کار می‌کند: به محض پیدا شدن اولین مقسوم‌علیه، جواب معلوم است. با یک متغیر بولی (پرچم) و break، به‌محض معلوم شدن جواب از حلقه بیرون می‌آییم:

is_prime = True
for i in range(2, n):
    if n % i == 0:
        is_prime = False
        break

و یک نکته که در گام آخر دیدی: همیشه با ورودی‌های مرزی تست کن (۰، ۱، منفی، خیلی بزرگ). نسخه‌های ساده برای n = 1 جواب غلط می‌دهند، چون حلقه اصلاً اجرا نمی‌شود.

در درس تمرین حلقه همین مسئله با چهار نسخه حل شده؛ نسخهٔ آخر فقط تا جذر n می‌گردد و برای اعداد بزرگ هزار برابر سریع‌تر است.

  1. ۱گام ۱

    عدد را با input() بگیر، به عدد صحیح تبدیل کن و در متغیر n بگذار: n = int(input()).

    ورودی آزمایشی 13 است.

  2. ۲گام ۲

    عدد اول عددی است که فقط بر ۱ و خودش بخش‌پذیر باشد. پس اگر بشماریم چند عددِ بین ۲ تا n-1 بر n بخش‌پذیرند، جواب معلوم می‌شود.

    یک شمارندهٔ divisors = 0 بساز و با حلقهٔ for روی range(2, n) بگرد؛ هر جا n % i == 0 بود، یکی به شمارنده اضافه کن. آخر حلقه divisors را چاپ کن. برای 13 باید 0 چاپ شود.

  3. ۳گام ۳

    حالا نتیجه را خوانا کن: خط print(divisors) را پاک کن و به‌جایش با if و else تصمیم بگیر:

    اگر divisors == 0 بود، متن اول است را چاپ کن، وگرنه متن اول نیست.

  4. ۴گام ۴

    این برنامه برای 1000 بی‌دلیل 998 دور می‌زند، در حالی که از همان مقسوم‌علیهٔ اول معلوم است اول نیست!

    با پرچم و break سریعش کن: یک متغیر بولی is_prime = True بساز؛ داخل حلقه، به محض پیدا شدن مقسوم‌علیه آن را False کن و همان‌جا با break از حلقه بیرون بیا. تصمیم چاپ را بعد از حلقه با if is_prime بگیر.

  5. ۵گام ۵

    یک اشکال پنهان: با ورودی 1 (یا 0) برنامه غلط می‌گوید «اول است»، چون حلقه اصلاً نمی‌چرخد و پرچم همان True می‌ماند!

    درستش کن: قبل از حلقه بررسی کن؛ اگر n < 2 بود، مستقیم اول نیست چاپ شود (بدون حلقه). می‌توانی این حالت را در یک شاخهٔ if/else بزرگ بگذاری: یک شاخه برای n < 2 و شاخهٔ دیگر برای حلقه و پرچم.

در حال آماده‌سازی ویرایشگر…