التنفيذ المتكرر
الجهاز الحقيقي لا يقيس مرة واحدة ثم يتوقف: المحطة تقرأ جهد البطارية مرة بعد مرة، والشاحن يفحص التيار ما دام يعمل، والمتحكّم يعيد الأوامر نفسها طوال اليوم. في هذا الفصل نعلّم البرنامج أن يكرر، وأن يعرف متى يتوقف، وأن يستخرج من سلسلة طويلة من القراءات عددها ومجموعها وأكبرها وأصغرها.
- نميّز بين وصف الحلقة بالكلمات وكتابتها بالشيفرة، ونكتب حلقة while بأجزائها الثلاثة.
- نكتب مصفاة مُدخَلات عنيدة، ونقرأ كمية غير معروفة من المعطيات حتى قيمة توقّف.
- نترجم شرط الإنهاء، البسيط والمركب، إلى شرط الحلقة.
- نستعمل العدّاد والمُجمِّع والقيم القصوى، وحدها أو مجتمعة.
- نكتشف الحلقة اللانهائية، ونفحص صحّة البرنامج ونجاعته بجدول المتابعة.
- نكتب حلقة داخل حلقة، ونمزج بين الشروط والحلقات.
4.1 الحاجة إلى التنفيذ المتكرر – הצורך בביצוע חוזר
نريد متوسط ثلاث قراءات لحسّاس. بما تعلمناه حتى الآن نكتب الأمرين نفسيهما ثلاث مرات:
total = 0
value = float(input("Sample: "))
total += value
value = float(input("Sample: "))
total += value
value = float(input("Sample: "))
total += value
print("Average:", total / 3)البرنامج صحيح، لكنه لا يصلح إذا صارت القراءات مئة. سنضطر إلى نسخ مئتي سطر، وأي تصحيح سيتكرر مئة مرة. والأسوأ من ذلك أننا أحيانا لا نعرف العدد مسبقا: كم قراءة ستصل قبل أن يوقف المستخدم الجهاز؟ لا يوجد عدد نسخ يكفي لسؤال كهذا.
البرنامج نفسه بحلقة أقصر، ويكفي أن نغيّر فيه عددين كي يقرأ مئة قيمة. سنشرح كل سطر فيه في البند التالي:
total = 0
n = 1
while n <= 3:
value = float(input("Sample: "))
total += value
n += 1
print("Average:", total / 3)Sample: 20.5 Sample: 21 Sample: 21.5 Average: 21.0
وهناك حالة ثانية لا تحلها أي نسخة، لأن عدد الدورات ينتج عن الحساب نفسه:
- نبدأ بجهد 12 V وبعدد فترات يساوي صفرا.
- ما دام الجهد لا يقل عن 1 V: نقسم الجهد على 2، ونزيد عدد الفترات بواحد.
- نطبع عدد الفترات والجهد.
لا يظهر في الخوارزمية أي عدد للدورات، وما يحدد نهايتها هو الشرط. وبالشيفرة:
volts = 12.0
steps = 0
while volts >= 1:
volts = volts / 2
steps += 1
print("Steps:", steps)
print("Volts:", volts)Steps: 4 Volts: 0.75
4.2 البنية الأساسية للحلقة while – תחביר בסיסי של לולאת while
الأمر while يعني «ما دام». نكتبه هكذا:
while condition:
statement
statement
next_statement- بعد الشرط نقطتان
:، كما فيif، وبدونهما لا يبدأ البرنامج. - الأوامر المزاحة هي جسم الحلقة (גוף הלולאה)، وهي التي تتكرر.
- يُفحص الشرط قبل كل دورة. إذا تحقّق نُفِّذ الجسم كله ثم عدنا إلى الشرط، وإذا لم يتحقّق انتقلنا إلى الأمر الذي بعد الجسم.
blink = 1
while blink <= 3:
print("LED blink", blink)
blink += 1
print("Test finished")LED blink 1 LED blink 2 LED blink 3 Test finished
| الأمر | blink | blink <= 3 | المُخرَج |
|---|---|---|---|
| blink = 1 | 1 | ||
| while blink <= 3: | True | ||
| print("LED blink", blink) | LED blink 1 | ||
| blink += 1 | 2 | ||
| while blink <= 3: | True | ||
| print("LED blink", blink) | LED blink 2 | ||
| blink += 1 | 3 | ||
| while blink <= 3: | True | ||
| print("LED blink", blink) | LED blink 3 | ||
| blink += 1 | 4 | ||
| while blink <= 3: | False | ||
| print("Test finished") | Test finished |
نقرأ الجدول من الأعلى إلى الأسفل. يظهر الشرط أربع مرات والجسم ثلاث مرات: ثلاث مرات تحقّق فيها، وفي المرة الرابعة لم يتحقّق فانتهت الحلقة. وعند الخروج تكون قيمة blink تساوي 4، لا 3.
قد لا يُنفَّذ الجسم ولا مرة: إذا لم يتحقّق الشرط من البداية ننتقل مباشرة إلى ما بعد الحلقة.
volts = 3.0
while volts > 5:
print("Too high")
volts -= 1
print("Volts:", volts)Volts: 3.0
والتحديث لا يعني دائما زيادة واحد. نستطيع أن نزيد بأي خطوة، مثل volts += 3، وأن ننقص في العدّ التنازلي، مثل left -= 1.
الكتابة الخوارزمية والكتابة بالشيفرة – כתיבה אלגוריתמית ומימוש בקוד:
حين نصف حلقة بالكلمات نذكر ما نريد، وننتبه إلى المعنى فقط. أما الشيفرة فتطلب كل التفاصيل التي تركناها: متغيّرا يعدّ، قيمته الأولى، وأمر تحديثه. نكتب الوصف أولا، ثم نسأل أنفسنا عن كل جملة فيه: ما المتغيّر الذي يمثلها؟
| الوصف بالكلمات | الشيفرة | ما أضافته الشيفرة |
|---|---|---|
| كرّر خمس مرات | n = 1 ، while n <= 5: ، n += 1 | عدّاد بتهيئته وتحديثه |
| ما دام الجهد أقل من 12 V | while volts < 12: | القيمة الأولى لـ volts وتحديثها |
حتى يكتب المستخدم -1 | while x != -1: | قلب الشرط، وأمر قراءة داخل الجسم |
ننتبه إلى الفرق في السطر الأخير: في الكلام نقول «حتى» ونذكر متى نتوقف، أما while فيسأل متى نستمر. سنعود إلى هذه الترجمة في البند 4.5.
n قبل الطباعة، فنحصل على 2 و3 و4 بدل 1 و2 و3:n = 1
while n <= 3:
n += 1
print("Sample", n)Sample 2 Sample 3 Sample 4
وسطر واحد خارج الإزاحة يخرج من الجسم. الأمر print هنا لا يتكرر، ويُنفَّذ مرة واحدة بعد انتهاء الحلقة:
n = 1
while n <= 3:
n += 1
print("Sample", n)Sample 4
n = 1
total = 0
while n < 4:
total += n
n += 1
print(n, total)4.3 مصفاة المُدخَلات العنيدة – מסננת קלט עקשנית (do while)
في البند 3.10 كتبنا مصفاة مُدخَلات تفحص القيمة مرة واحدة ثم تستسلم: إذا كانت القيمة خاطئة طبعنا رسالة وانتهى كل شيء. الآن نستطيع أن نفعل ما يفعله كل جهاز جيد: نسأل مرة بعد مرة حتى يصل مُدخَل صحيح.
في هذه المهمة يجب أن نقرأ مرة واحدة على الأقل، ثم نقرر هل نعيد. لهذا الشكل بنية خاصة في لغات أخرى اسمها do while، تنفّذ الجسم أولا ثم تفحص الشرط، وهو الاسم الذي تذكره خطة التعليم. في بايثون لا توجد هذه البنية، ولذلك نكتب المصفاة بإحدى طريقتين.
الطريقة الأولى: قراءة قبل الحلقة وقراءة داخلها:
نقرأ مرة قبل الحلقة، فيكون عند الشرط ما يفحصه. وشرط الحلقة يصف القيمة غير الصالحة:
adc = int(input("ADC (0-1023): "))
while adc < 0 or adc > 1023:
print("Out of range, try again")
adc = int(input("ADC (0-1023): "))
print("Accepted:", adc)ADC (0-1023): 1500 Out of range, try again ADC (0-1023): -4 Out of range, try again ADC (0-1023): 512 Accepted: 512
| الأمر | adc | adc < 0 or adc > 1023 | المُخرَج |
|---|---|---|---|
| adc = int(input("ADC (0-1023): ")) | 1500 | ADC (0-1023): 1500 | |
| while adc < 0 or adc > 1023: | True | ||
| print("Out of range, try again") | Out of range, try again | ||
| adc = int(input("ADC (0-1023): ")) | 512 | ADC (0-1023): 512 | |
| while adc < 0 or adc > 1023: | False | ||
| print("Accepted:", adc) | Accepted: 512 |
الطريقة الثانية: حلقة بشرط True وخروج بالأمر break:
الشرط True يتحقّق دائما، فنقرأ مرة واحدة داخل الجسم. والأمر break يخرج من الحلقة فورا، وسنتعرف إليه بالتفصيل في البند 4.7. الشرط هنا يصف القيمة الصالحة، وهو عكس شرط الطريقة الأولى:
while True:
adc = int(input("ADC (0-1023): "))
if 0 <= adc <= 1023:
break
print("Out of range, try again")
print("Accepted:", adc)| قراءة مزدوجة | while True | |
|---|---|---|
| عدد أوامر القراءة | أمران متطابقان | أمر واحد |
| الشرط يصف | القيمة المرفوضة، ونستمر ما دام يتحقّق | القيمة المقبولة، ونخرج عندما يتحقّق |
| متى نفضّلها | حين يكون الشرط قصيرا والقراءة بسيطة | حين تطول القراءة أو تسبقها رسالة |
مُخرَج الطريقة الثانية مطابق لمُخرَج الأولى. كلتاهما صحيحة، ونستعملهما معا في هذا الكتاب. وفي الامتحان نختار ما نرتاح إليه.
if بدل while يعطي فرصة واحدة فقط. القيمة الثانية تُقبل بلا فحص، ولو كانت خارج المجال أيضا:adc = int(input("ADC (0-1023): "))
if adc < 0 or adc > 1023:
adc = int(input("ADC (0-1023): "))
print("Accepted:", adc)ADC (0-1023): 1500 ADC (0-1023): 2000 Accepted: 2000
duty بين 0 و100، ثم تطبعها.4.4 قراءة كمية غير معروفة من المعطيات – קליטת כמות לא ידועה של נתונים (תבנית קלט עם זקיף)
الفني يسجّل قدرات الأجهزة المتصلة بالخط واحدا بعد الآخر، ولا يعرف عددها مسبقا. كيف يخبر البرنامج بأنه انتهى؟ يكتب قيمة متفقا عليها لا يمكن أن تكون معطى حقيقيا.
total = 0
watts = float(input("Load W (0 stops): "))
while watts != 0:
total += watts
watts = float(input("Load W (0 stops): "))
print("Total:", total, "W")Load W (0 stops): 60 Load W (0 stops): 100 Load W (0 stops): 25 Load W (0 stops): 0 Total: 185.0 W
| الأمر | total | watts | watts != 0 | المُخرَج |
|---|---|---|---|---|
| total = 0 | 0 | |||
| watts = float(input("Load W (0 stops): ")) | 60.0 | Load W (0 stops): 60 | ||
| while watts != 0: | True | |||
| total += watts | 60.0 | |||
| watts = float(input("Load W (0 stops): ")) | 25.0 | Load W (0 stops): 25 | ||
| while watts != 0: | True | |||
| total += watts | 85.0 | |||
| watts = float(input("Load W (0 stops): ")) | 0.0 | Load W (0 stops): 0 | ||
| while watts != 0: | False | |||
| print("Total:", total, "W") | Total: 85.0 W |
نلاحظ أن أمر القراءة هو آخر ما في الجسم. بعده مباشرة يأتي فحص الشرط، فلا تصل قيمة التوقّف إلى أمر الجمع. وإذا كانت أول قيمة هي قيمة التوقّف، لا يُنفَّذ الجسم أبدا، ويطبع البرنامج: Total: 0 W
وبالطريقة الثانية من البند السابق نكتب أمر قراءة واحدا: نبدأ الجسم بالقراءة، ثم نفحص قيمة التوقّف ونخرج بالأمر break، ثم نجمع. الفحص يأتي قبل أي حساب.
30، لكن البرنامج يطبع قيمة أقل بواحد:total = 0
pulses = 1
while pulses != -1:
pulses = int(input("Pulses (-1 stops): "))
total += pulses
print("Total:", total)Pulses (-1 stops): 10 Pulses (-1 stops): 20 Pulses (-1 stops): -1 Total: 29
قيمة التوقّف قد تكون جملة نصية أيضا. نقرأ أسماء قطع إلكترونية حتى الكلمة end، ولا نحوّل المُدخَل إلى عدد:
count = 0
part = input("Part (end stops): ")
while part != "end":
count += 1
print("Stored:", part)
part = input("Part (end stops): ")
print("Parts:", count)Part (end stops): LM358 Stored: LM358 Part (end stops): 7805 Stored: 7805 Part (end stops): end Parts: 2
-1 لقراءة حرارة، لأن -1 درجة قيمة حقيقية في الشتاء، فيتوقف البرنامج قبل الأوان. نختار 999، وهي بعيدة عن كل حرارة يقيسها الحسّاس.x = int(input("x: "))
y = 0
while x != 0:
y += x * 2
x = int(input("x: "))
print(y)4.5 ترجمة شرط الإنهاء إلى شرط الحلقة – תרגום תנאי סיום לתנאי הלולאה
السؤال في الامتحان وفي الحياة يصف عادة متى نتوقف: «توقف عندما يصل المجموع إلى كذا، أو بعد كذا قراءة». أما while فيحتاج إلى متى نستمر. لذلك نترجم:
| نتوقف عندما | نستمر ما دام | ماذا حدث |
|---|---|---|
x == -1 | x != -1 | المساواة تصبح عدم مساواة |
total >= 100 | total < 100 | نقلب المقارنة، ولا ننسى حالة التساوي |
v < 0 or v > 5 | v >= 0 and v <= 5 | نقلب كل مقارنة، وor تصبح and |
a == 0 and b == 0 | a != 0 or b != 0 | نقلب كل مقارنة، وand تصبح or |
العمود الثالث في السطرين الأخيرين هو ما نعرفه من الأنظمة الرقمية باسم قانوني دي مورغان (חוקי דה-מורגן): عندما ننفي شرطا مركبا، ننفي كل طرف فيه، ونبدّل and بـor والعكس. نفحص ذلك لكل القيم الممكنة:
| a | b | not (a or b) | not a and not b | not (a and b) | not a or not b |
|---|---|---|---|---|---|
| False | False | True | True | True | True |
| False | True | False | False | True | True |
| True | False | False | False | True | True |
| True | True | False | False | False | False |
العمودان الثالث والرابع متطابقان، وكذلك الخامس والسادس.
| الشرط | |
|---|---|
| نتوقف عندما | total >= 256 or packets >= 5 |
| نستمر ما دام | total < 256 and packets < 5 |
total = 0
packets = 0
while total < 256 and packets < 5:
size = int(input("Packet bytes: "))
total += size
packets += 1
print("Bytes:", total)
print("Packets:", packets)Packet bytes: 100 Packet bytes: 120 Packet bytes: 90 Bytes: 310 Packets: 3
توقف البرنامج هنا بسبب البايتات، بعد ثلاث رزم. ومع خمس رزم صغيرة كل منها 10 بايتات يتوقف بسبب العدد، ويطبع: Bytes: 50 , Packets: 5
وإذا صعبت علينا الترجمة، نستطيع أن نكتب النفي كما هو بالمعامل not حول شرط الإنهاء: while not (total >= 256 or packets >= 5):. الحساب نفسه، والنتيجة نفسها.
or تتحول إلى and، فنكتب or بين الشرطين. عندها تستمر الحلقة ما دام أحدهما لم يصل إلى حدّه، أي حتى يتحقّق الشرطان معا. للرزم الثلاث نفسها لا يتوقف البرنامج، بل يطلب رزمتين أخريين، ويطبع في النهاية: Bytes: 330 , Packets: 5وهذا الخطأ أخطر في صورة أخرى. نريد مصفاة تقبل الوضع 1 أو 2، فنكتب while mode != 1 or mode != 2:. هذه الحلقة لا تنتهي أبدا: كل عدد يختلف عن 1 أو يختلف عن 2، فالشرط يتحقّق دائما حتى عندما يكتب المستخدم قيمة صحيحة. نعود إلى القاعدة: نتوقف عندما mode == 1 or mode == 2، فنكتب while mode != 1 and mode != 2:.
code = int(input("Code: "))
tries = 1
while code != 4071 and tries < 3:
code = int(input("Code: "))
tries += 1
if code == 4071:
print("Unlocked")
else:
print("Locked")Code: 1111 Code: 4071 Unlocked
وبعد ثلاث محاولات خاطئة يطبع: Locked
a = 2 وb = 5not (a > 3 or b > 3)a <= 3 and b <= 3not (a > 3 and b > 3)a <= 3 or b <= 3not a == 2not (a == 2 or b == 2)False 2 False 3 True 4 True 5 False 6 False 4.6 مهام حسابية نموذجية – משימות חישוב טיפוסיות
معظم الحلقات في البرامج تفعل واحدا من أشياء قليلة: تعدّ، أو تجمع، أو تبحث عن الأكبر والأصغر. نتعلم كل واحد منها كنمط جاهز، ثم نمزجها. وفي كل نمط نسأل سؤالين: ما القيمة الأولى قبل الحلقة، وماذا يحدث في كل دورة؟
العدّاد – מונה:
value = int(input("Largest value: "))
bits = 0
while value > 0:
value = value // 2
bits += 1
print("Bits needed:", bits)Largest value: 1023 Bits needed: 10
وللقيمة 1024 يطبع: Bits needed: 11، لأن 1024 يحتاج إلى خانة إضافية.
العدّاد مع شرط – מונה עם תנאי:
العدّاد مع شرط لا يزيد في كل دورة، بل فقط عندما يتحقّق الشرط. مكانه هو if داخل جسم الحلقة:
limit = 10
over = 0
amps = float(input("Current (-1 stops): "))
while amps != -1:
if amps > limit:
over += 1
amps = float(input("Current (-1 stops): "))
print("Over the limit:", over)Current (-1 stops): 8.5 Current (-1 stops): 12 Current (-1 stops): 10.4 Current (-1 stops): -1 Over the limit: 2
المُجمِّع – צובר:
رأينا المُجمِّع في البند 4.4، حين جمعنا قدرات الأجهزة بالأمر total += watts.
الفرق بين العدّاد والمُجمِّع بسيط: العدّاد يضيف واحدا، والمُجمِّع يضيف القيمة نفسها. وهناك مُجمِّع يضرب بدل أن يجمع، وعندها لا يصح أن يبدأ من الصفر:
gain = 1
stage = float(input("Stage gain (0 stops): "))
while stage != 0:
gain *= stage
stage = float(input("Stage gain (0 stops): "))
print("Total gain:", gain)Stage gain (0 stops): 10 Stage gain (0 stops): 5 Stage gain (0 stops): 0 Total gain: 50.0
المتوسط يحتاج إلى النمطين معا: مُجمِّع يحمل المجموع، وعدّاد يحمل عدد القيم. وبما أن عدد القيم قد يكون صفرا، نفحصه قبل القسمة:
count = 0
total = 0
temp = float(input("Temp (999 stops): "))
while temp != 999:
count += 1
total += temp
temp = float(input("Temp (999 stops): "))
if count > 0:
print("Average:", round(total / count, 2))
else:
print("No readings")Temp (999 stops): 22.5 Temp (999 stops): 24 Temp (999 stops): 19.5 Temp (999 stops): 999 Average: 22.0
القيم القصوى – ערכי קיצון:
v = float(input("Volts (0 stops): "))
high = v
low = v
while v != 0:
if v > high:
high = v
if v < low:
low = v
v = float(input("Volts (0 stops): "))
print("Ripple:", round(high - low, 2), "V")Volts (0 stops): 11.9 Volts (0 stops): 12.3 Volts (0 stops): 11.7 Volts (0 stops): 0 Ripple: 0.6 V
قيمة التوقّف لا تدخل في المقارنة، لأن الشرط يُفحص مباشرة بعد قراءتها.
-3، لكنه يطبع قيمة لم يقرأها أصلا:top = 0
temp = int(input("Temp (999 stops): "))
while temp != 999:
if temp > top:
top = temp
temp = int(input("Temp (999 stops): "))
print("Highest:", top)Temp (999 stops): -7 Temp (999 stops): -3 Temp (999 stops): -12 Temp (999 stops): 999 Highest: 0
الحل هو أن تكون القيمة الأولى قراءة حقيقية: نقرأ أولا، ثم نكتب top = temp قبل الحلقة، فيطبع البرنامج Highest: -3.
المزج بين المهام – שילוב בין המשימות:
-1. نطبع المتوسط، أعلى قدرة ورقم الساعة التي ظهرت فيها.نحتاج إلى عدّاد للساعات، مُجمِّع وقيمة قصوى مع موقعها. كل واحد منها سطر أو سطران من الأنماط التي تعلمناها:
hour = 0
total = 0
watts = float(input("Panel W (-1 stops): "))
while watts != -1:
hour += 1
total += watts
if hour == 1 or watts > peak:
peak = watts
peak_hour = hour
watts = float(input("Panel W (-1 stops): "))
if hour > 0:
print("Average:", round(total / hour, 1), "W")
print("Peak:", peak, "W at hour", peak_hour)Panel W (-1 stops): 60 Panel W (-1 stops): 110 Panel W (-1 stops): 135 Panel W (-1 stops): 90 Panel W (-1 stops): -1 Average: 98.8 W Peak: 135.0 W at hour 3
نلاحظ الشرط hour == 1 or watts > peak: في الساعة الأولى لا يوجد بعد peak، لكن اختصار الطريق من البند 3.5 يمنع حساب الطرف الأيمن، فلا يقع خطأ.
| المهمة | قبل الحلقة | داخل الحلقة |
|---|---|---|
| عدّاد | count = 0 | count += 1 |
| عدّاد مع شرط | count = 0 | if ok: count += 1 |
| مُجمِّع بالجمع | total = 0 | total += x |
| مُجمِّع بالضرب | gain = 1 | gain *= x |
| الأكبر | top = first | if x > top: top = x |
| الأصغر | low = first | if x < low: low = x |
| المتوسط | مُجمِّع وعدّاد | بعد الحلقة: total / count |
a وb؟a = 0
b = 0
x = int(input("x: "))
while x != 0:
a += 1
if x > 5:
b += x
x = int(input("x: "))
print(a, b)4.7 الأمران break وcontinue – הפקודות break ו-continue
| الأمر | عمله |
|---|---|
| break | يخرج من الحلقة فورا، وينتقل إلى الأمر الذي بعدها |
| continue | يترك بقية الجسم في هذه الدورة، ويعود إلى فحص الشرط |
الأمران يظهران دائما تقريبا داخل if، لأننا نقفز عند حالة خاصة فقط.
cell = 1
while cell <= 6:
v = float(input("Cell V: "))
if v < 3.0:
print("Weak cell:", cell)
break
cell += 1
print("Scan finished")Cell V: 3.7 Cell V: 3.6 Cell V: 2.8 Weak cell: 3 Scan finished
يمكن أن نكتب البرنامج نفسه بلا break، بعلم (דגל) بولياني weak نغيّره إلى True عند الخلية الضعيفة، وبشرط مركب هو ترجمة «نتوقف عند خلية ضعيفة أو بعد ست خلايا»: while cell <= 6 and not weak:
الأمر break يجعل البرنامج أقصر، والشرط المركب يجعل سبب الخروج ظاهرا في رأس الحلقة. وكلاهما مقبول.
-1، ونحسب المتوسط. القراءة الأكبر من 1023 ناتجة عن تشويش، فنتجاهلها ولا ندخلها في الحساب.total = 0
count = 0
while True:
adc = int(input("ADC (-1 stops): "))
if adc == -1:
break
if adc > 1023:
print("Ignored:", adc)
continue
total += adc
count += 1
if count > 0:
print("Average:", total / count)
else:
print("No readings")ADC (-1 stops): 500 ADC (-1 stops): 2000 Ignored: 2000 ADC (-1 stops): 520 ADC (-1 stops): -1 Average: 510.0
في الدورة الثانية نفّذ البرنامج continue، فلم يصل إلى الجمع ولا إلى العدّاد.
continue قبل تحديث العدّاد، فلا يتغيّر العدّاد أبدا بعد القفز، ويدور البرنامج في مكانه عند القناة الثالثة:ch = 1
while ch <= 4:
if ch == 3:
continue
print("Channel", ch)
ch += 1نحدّث العدّاد في أول الجسم، قبل أي قفز:
ch = 0
while ch < 4:
ch += 1
if ch == 3:
continue
print("Channel", ch)Channel 1 Channel 2 Channel 4
n = 0
while n < 6:
n += 1
if n == 2:
continue
if n == 5:
break
print(n)
print("end", n)4.8 التنفيذ اللانهائي – ביצוע אינסופי
Ctrl+C، وفي Google Colab بزر الإيقاف بجانب الخلية.البرامج في هذا البند لا تنتهي، ولذلك نعرضها بلا مُخرَج. لكل منها سبب مختلف، ونتعلم أن نبحث عنه:
n = 1
while n <= 3:
print("Sample", n)n = 1
while n <= 3:
print("Sample", n)
n += 1volts = 12
while volts > 0:
print(volts)
volts += 3x = 0.0
while x != 1.0:
x += 0.1البرنامج الأخير يحتاج إلى شرح. بعد عشر دورات نتوقع أن تكون القيمة 1، لكننا تعلمنا في البند 3.3 أن الأعداد العشرية لا تُحفظ بدقة تامة. القيمة تمرّ قريبا جدا من 1 ولا تساويها، ثم تتجاوزها وتبتعد:
x = 0.0
n = 0
while n < 10:
x += 0.1
n += 1
print(x)
print(x == 1.0)0.9999999999999999 False
لا نكتب != في شرط الحلقة مع عدد عشري ناتج عن حساب. نفحص الاقتراب بسماح، أو نعدّ الدورات بعدد صحيح كما في البرنامج أعلاه. الشرط while abs(x - 1.0) > 0.001: ينتهي بعد عشر دورات بالضبط. أما قيمة التوقّف التي نقرؤها من المُدخَل، كما في البند 4.4، فحالة أخرى: لم نحسبها، ولذلك تكون المقارنة بها دقيقة.
حلقة لا نهائية مقصودة:
ليست كل حلقة لا نهائية خطأ. البرنامج الذي يدير جهازا لا ينتهي إلا عند فصل الكهرباء: يقرأ، يعرض وينتظر، ثم يعيد. هكذا تعمل العمليّة loop في أردوينو التي نتعرف إليها في الأنظمة المدمجة، وهكذا تعمل المحطة عندما تصبح جهازا حقيقيا. نعرض الفكرة، والعمليّات فيها أسماء توضيحية فقط:
while True:
adc = read_sensor()
show_on_display(adc)
wait_one_second()وفي الأجهزة نضيف كثيرا ما يسمى حارسا: حدا أعلى لعدد الدورات. السخّان يجب أن يبلغ 60 درجة، لكن إذا لم يبلغها خلال 30 دقيقة فلا ننتظر إلى الأبد، بل نعلن خللا:
temp = 20
minutes = 0
while temp < 60 and minutes < 30:
temp += 6
minutes += 1
if temp >= 60:
print("Ready after", minutes, "min")
else:
print("Heater fault")Ready after 7 min
k = 10
while k > 0:
k = k - 4k = 10
while k != 0:
k = k - 4k = 1
while k > 0:
k = k + 14.9 تحليل صحّة البرنامج بجدول المتابعة – ניתוח נכונות בעזרת טבלת מעקב
جدول المتابعة يكشف ما يحدث فعلا، لا ما نظن أنه يحدث. وفي الحلقة نقرأه هكذا: ما قيمة كل متغيّر عند أول فحص للشرط؟ وما قيمته عند آخر دورة؟ وما قيمته بعد الخروج؟ أكثر أخطاء الحلقات تقع في البداية أو في النهاية، أي تكون زيادة دورة أو نقصانها.
-1، ولكنه يعطي للقيمتين 10 و20 النتيجة 10.0 بدل 15.0. نبحث عن الخطأ.count = 1
total = 0
v = int(input("V (-1 stops): "))
while v != -1:
total += v
count += 1
v = int(input("V (-1 stops): "))
print(total / count)| الأمر | count | total | v | v != -1 | المُخرَج |
|---|---|---|---|---|---|
| count = 1 | 1 | ||||
| total = 0 | 0 | ||||
| v = int(input("V (-1 stops): ")) | 10 | V (-1 stops): 10 | |||
| while v != -1: | True | ||||
| total += v | 10 | ||||
| count += 1 | 2 | ||||
| v = int(input("V (-1 stops): ")) | 20 | V (-1 stops): 20 | |||
| while v != -1: | True | ||||
| total += v | 30 | ||||
| count += 1 | 3 | ||||
| v = int(input("V (-1 stops): ")) | -1 | V (-1 stops): -1 | |||
| while v != -1: | False | ||||
| print(total / count) | 10.0 |
نقرأ العمود count عند الخروج: قيمته 3، مع أننا قرأنا قيمتين فقط. السبب في السطر الأول: العدّاد يبدأ من 1. نصلحه ليبدأ من الصفر.
بعد التصحيح ينجح المثال، لكن هذا لا يكفي. نجرب أيضا الحالات الحدّية (מקרי קצה): لا قيم أبدا، أو قيمة واحدة فقط. وهنا يظهر خطأ جديد. إذا كانت أول قيمة هي قيمة التوقّف، تنهار القسمة:
count = 0
total = 0
v = int(input("V (-1 stops): "))
while v != -1:
total += v
count += 1
v = int(input("V (-1 stops): "))
print(total / count)V (-1 stops): -1 ZeroDivisionError: division by zero
نستبدل أمر الطباعة الأخير بالفحص الذي تعلمناه، فنحصل على برنامج يصمد أمام هذه الحالات. نعرض البديل ونتيجة كل فحص في البرنامج الكامل:
if count > 0:
print(total / count)
else:
print("No readings")| الفحص | المُدخَل | المتوقع | المُخرَج الأخير |
|---|---|---|---|
| حالة عادية | 10, 20, -1 | 15.0 | 15.0 |
| قيمة واحدة | 10, -1 | 10.0 | 10.0 |
| لا قيم | -1 | رسالة | No readings |
| قيم متساوية | 7, 7, 7, -1 | 7.0 | 7.0 |
وهناك خطأ حدّي شائع جدا، هو خطأ الدورة الواحدة. يجب أن تطبع الحلقة التالية ثلاث قراءات، لكن n < 3 يتوقف قبل الثالثة:
n = 1
while n < 3:
print("Sample", n)
n += 1
print("n =", n)Sample 1 Sample 2 n = 3
عند الخروج من حلقة ليس فيها break نعرف دائما شيئا مؤكدا: شرط الحلقة لم يعد يتحقّق. هنا يعني ذلك n >= 3، وهذه طريقة سريعة للفحص: نسأل هل الوضع عند الخروج هو ما أردناه.
النجاعة – יעילות:
target = int(input("Value: "))
guess = 0
steps = 0
while guess < target:
guess += 1
steps += 1
print("Found", guess, "in", steps, "steps")Value: 731 Found 731 in 731 steps
الطريقة الثانية تبدأ بالمنتصف، وتسأل هل العدد المطلوب أعلى أم لا، وتحذف نصف المجال في كل دورة. هذه هي فكرة المحوّل بالتقريب المتتالي (ממיר קירוב עוקב)، المنتشر في المتحكّمات. يطبع البرنامج حدّي المجال بعد كل دورة:
target = int(input("Value: "))
low = 0
high = 1023
steps = 0
while low < high:
mid = (low + high) // 2
if mid < target:
low = mid + 1
else:
high = mid
steps += 1
print(low, high)
print("Found", low, "in", steps, "steps")Value: 731 512 1023 512 767 640 767 704 767 704 735 720 735 728 735 728 731 730 731 731 731 Found 731 in 10 steps
| العدد المطلوب | الطريقة الأولى | الطريقة الثانية |
|---|---|---|
10 | Found 10 in 10 steps | Found 10 in 10 steps |
731 | Found 731 in 731 steps | Found 731 in 10 steps |
1023 | Found 1023 in 1023 steps | Found 1023 in 10 steps |
النتيجة نفسها، وكلا البرنامجين صحيح. لكن الطريقة الثانية تكتفي دائما بعشر دورات، وهو عدد الخانات التي احتجنا إليها في البند 4.6، بينما قد تحتاج الطريقة الأولى إلى 1023 دورة.
break أو بشرط مركب. ولا نضع في الجسم حسابا لا يتغيّر من دورة إلى دورة. مثلا نحسب step = 5 / 1023 مرة واحدة قبل الحلقة في المحطة.4.10 التداخل والمزج بين if وwhile – קינון ושילוב מבני if, while
جسم الحلقة يمكن أن يحتوي أي أمر، وكذلك جسم الشرط. هذا هو التداخل (קינון). وقد استعملنا if داخل while طوال الفصل، ويمكن أيضا أن نضع حلقة في فرع من شرط إذا لم نكن نحتاج إليها إلا في حالة معيّنة. وكل مستوى تداخل يضيف إزاحة.
شروط متسلسلة داخل حلقة:
elif في الجسم.volts = 12.0
choice = int(input("1 up, 2 down, 0 exit: "))
while choice != 0:
if choice == 1:
volts += 0.5
elif choice == 2:
volts -= 0.5
else:
print("Unknown choice")
print("Output:", volts, "V")
choice = int(input("1 up, 2 down, 0 exit: "))
print("Bye")1 up, 2 down, 0 exit: 1 Output: 12.5 V 1 up, 2 down, 0 exit: 2 Output: 12.0 V 1 up, 2 down, 0 exit: 7 Unknown choice Output: 12.0 V 1 up, 2 down, 0 exit: 0 Bye
حلقة داخل حلقة:
عندما توضع حلقة داخل حلقة، تُنفَّذ الحلقة الداخلية كلها في كل دورة من دورات الخارجية. تشبه عقربي الساعة: عقرب الدقائق يدور دورة كاملة في كل خطوة من خطوات عقرب الساعات.
end يبقينا في السطر نفسه، وprint() الفارغ ينهي السطر.v = 3
while v <= 9:
print(v, "V:", end=" ")
r = 100
while r <= 300:
print(round(v / r * 1000, 1), end=" ")
r += 100
print()
v += 33 V: 30.0 15.0 10.0 6 V: 60.0 30.0 20.0 9 V: 90.0 45.0 30.0
r = 100 إلى ما قبل الحلقة الخارجية، لبقيت r بعد أول سطر عند 400، فلا تعمل الحلقة الداخلية مرة أخرى، وتبقى بقية السطور فارغة: 3 V: 30.0 15.0 10.0 / 6 V: / 9 V: . التهيئة مكانها داخل الحلقة الخارجية، قبل الداخلية مباشرة.نتابع حلقتين متداخلتين. هنا حدّ الحلقة الداخلية يتعلق بعدّاد الخارجية، لذلك لا تُنفَّذ الداخلية في الدورة الأولى، وتُنفَّذ مرة في الثانية:
row = 1
while row <= 2:
col = 1
while col < row:
print(row, col)
col += 1
row += 1| الأمر | row | col | row <= 2 | col < row | المُخرَج |
|---|---|---|---|---|---|
| row = 1 | 1 | ||||
| while row <= 2: | True | ||||
| col = 1 | 1 | ||||
| while col < row: | False | ||||
| row += 1 | 2 | ||||
| while row <= 2: | True | ||||
| col = 1 | |||||
| while col < row: | True | ||||
| print(row, col) | 2 1 | ||||
| col += 1 | 2 | ||||
| while col < row: | False | ||||
| row += 1 | 3 | ||||
| while row <= 2: | False |
a = 1
while a <= 3:
b = a
while b <= 3:
print(a * b, end=" ")
b += 1
print()
a += 1break يخرج من الحلقة الداخلية فقط، وتستمر الخارجية كالمعتاد.key_row = 2
key_col = 2
found = False
row = 1
while row <= 4 and not found:
col = 1
while col <= 3 and not found:
print("Testing", row, col)
if row == key_row and col == key_col:
found = True
col += 1
row += 1
print("Key found:", found)Testing 1 1 Testing 1 2 Testing 1 3 Testing 2 1 Testing 2 2 Key found: True
في الفصلين السابقين قرأت المحطة قيمة واحدة وقررت. الآن تجمع قراءات المحوّل لجهد البطارية حتى قيمة التوقّف -1، ثم تكتب تقريرا: عدد العينات، متوسط الجهد، أدناه وأعلاه، وعدد العينات تحت 11.8 V. الحساب من الفصل 2 كما هو: خطوة المحوّل 5 / 1023، ومقسّم الجهد الذي يقسم على 4.
step = 5 / 1023
limit = 11.8
count = 0
total = 0
below = 0
adc = int(input("ADC battery (-1 stops): "))
while adc != -1:
volts = adc * step * 4
count += 1
total += volts
if count == 1 or volts > top:
top = volts
if count == 1 or volts < bottom:
bottom = volts
if volts < limit:
below += 1
adc = int(input("ADC battery (-1 stops): "))
if count > 0:
print("Samples:", count)
print("Average:", round(total / count, 2), "V")
print("Min:", round(bottom, 2), "V")
print("Max:", round(top, 2), "V")
print("Below limit:", below)
else:
print("No samples")ADC battery (-1 stops): 620 ADC battery (-1 stops): 633 ADC battery (-1 stops): 590 ADC battery (-1 stops): 578 ADC battery (-1 stops): -1 Samples: 4 Average: 11.83 V Min: 11.3 V Max: 12.38 V Below limit: 2
الحلقة تجمع كل ما تعلمناه: قيمة توقّف، عدّاد، مُجمِّع، عدّاد مع شرط وقيم قصوى. ونحسب الخطوة مرة واحدة قبل الحلقة. نجرّب بأنفسنا: ماذا يطبع البرنامج إذا كانت القراءة الأولى -1؟ وكيف نضيف مصفاة ترفض قراءة أكبر من 1023 بالأمر continue؟ ننتبه إلى أن القراءة التالية يجب أن تُقرأ قبل continue، وإلا دارت الحلقة في مكانها.
أهمّ أفكار الفصل:
- الحلقة تحتاج إلى تهيئة وشرط وتحديث. والشرط يُفحص قبل كل دورة، وقد لا يُنفَّذ الجسم أبدا.
- في بايثون لا يوجد
do while. نكتب المصفاة العنيدة بقراءة مزدوجة أو بالشكلwhile Trueمعbreak. - مع قيمة التوقّف نقرأ قبل الحلقة وفي آخر الجسم، فلا تدخل هذه القيمة في الحساب.
- شرط الحلقة هو نفي شرط الإنهاء: نقلب كل مقارنة، ونبدّل
orبـand. - العدّاد والمُجمِّع يبدآن من الصفر، ومُجمِّع الضرب من الواحد، والقيمة القصوى من أول قراءة حقيقية.
- جدول المتابعة والحالات الحدّية يكشفان أخطاء الحلقات، وعدد الدورات مقياس بسيط للنجاعة.
- في الحلقتين المتداخلتين تكون تهيئة الداخلية داخل الخارجية، و
breakيخرج من الداخلية فقط.
ملخّص أوامر الفصل:
| الأمر | عمله |
|---|---|
| while condition: | يكرر الجسم ما دام الشرط يتحقّق |
| while True: | حلقة لا تنتهي إلا بالأمر break |
| break | خروج فوري من الحلقة الأقرب |
| continue | ترك بقية الدورة والعودة إلى الشرط |
| count += 1 | تحديث عدّاد |
| total += x | تحديث مُجمِّع |
| while x != -1: | الاستمرار حتى قيمة التوقّف |
| print(x, end=" ") | الطباعة بلا انتقال إلى سطر جديد |
قاموس المصطلحات – מילון מונחים:
| بالعربية | بالعبرية (كما تظهر في الامتحان) | English |
|---|---|---|
| الحلقة | לולאה | Loop |
| التنفيذ المتكرر | ביצוע חוזר | Repeated execution |
| جسم الحلقة | גוף הלולאה | Loop body |
| الدورة | סבב (איטרציה) | Iteration |
| العدّاد | מונה | Counter |
| المُجمِّع | צובר | Accumulator |
| قيمة التوقّف | זקיף | Sentinel |
| مصفاة المُدخَلات | מסננת קלט | Input filter |
| المصفاة العنيدة | מסננת עקשנית | Persistent input filter |
| القيمة القصوى | ערך קיצון | Extreme value |
| شرط الإنهاء | תנאי סיום | Stop condition |
| قانونا دي مورغان | חוקי דה-מורגן | De Morgan laws |
| الحلقة اللانهائية | ביצוע אינסופי | Infinite loop |
| التداخل | קינון | Nesting |
| صحّة البرنامج | נכונות | Correctness |
| الحالة الحدّية | מקרה קצה | Edge case |
| النجاعة | יעילות | Efficiency |
4 6duty = int(input("Duty (0-100): "))
while duty < 0 or duty > 100:
duty = int(input("Duty (0-100): "))
print("Duty:", duty)120, 75 يطبع: Duty: 7516 ، 04 16. المتغيّر a عدّاد لكل القيم، وb مُجمِّع للقيم التي تزيد على 5.1 , 3 , 4 , end 5k تصل إلى قيمة سالبة. (ب) لا تنتهي: القيم هي 10, 6, 2, -2 ثم سالبة، فهي تتخطى الصفر ولا تساويه أبدا. (ج) لا تنتهي: k تكبر، والعدد الصحيح في بايثون بلا حد أقصى.1 2 3 / 4 6 / 9 أسئلة للتمرين:
k = 2
s = 0
while k < 10:
s += k
k = k + 3
print(k, s)11 15(أ) نتوقف عندما
x == 0.(ب) نتوقف عندما
t >= 100 or n == 20.(ج) نتوقف عندما
a < 0 and b < 0.x != 0 ، (ب) t < 100 and n != 20 ، (ج) a >= 0 or b >= 0ch = int(input("Channel (1-8): "))
while ch < 1 or ch > 8:
print("No such channel")
ch = int(input("Channel (1-8): "))
print("Reading channel", ch)9, 3 يطبع في النهاية: Reading channel 3n = 1 while n <= 4 print(n * 5) n =+ 1
+=. أما =+ فهي إسناد العدد الموجب 1، وتؤدي إلى حلقة لا نهائية:n = 1
while n <= 4:
print(n * 5)
n += 15 , 10 , 15 , 20x = int(input("x: "))
n = 0
while x > 1:
x = x // 3
n += 1
print(x, n)| الأمر | x | n | x > 1 | المُخرَج |
|---|---|---|---|---|
| x = int(input("x: ")) | 30 | x: 30 | ||
| n = 0 | 0 | |||
| while x > 1: | True | |||
| x = x // 3 | 10 | |||
| n += 1 | 1 | |||
| while x > 1: | True | |||
| x = x // 3 | 3 | |||
| n += 1 | 2 | |||
| while x > 1: | True | |||
| x = x // 3 | 1 | |||
| n += 1 | 3 | |||
| while x > 1: | False | |||
| print(x, n) | 1 3 |
inverse = 0
r = float(input("R (0 stops): "))
while r != 0:
inverse += 1 / r
r = float(input("R (0 stops): "))
if inverse > 0:
print("R total:", round(1 / inverse, 2))100, 300, 0 يطبع: R total: 75.0good = 0
count = 0
v = float(input("LED V (0 stops): "))
while v != 0:
count += 1
if 1.8 <= v <= 2.2:
good += 1
v = float(input("LED V (0 stops): "))
if count > 0:
print("Good:", good)
print("Percent:", round(good * 100 / count, 1))2.0, 1.5, 2.2, 2.5, 0 يطبع: Good: 2 , Percent: 50.0capacity = 100
years = 0
while capacity >= 80:
capacity = capacity * 0.97
years += 1
print("Years:", years)
print("Capacity:", round(capacity, 1))Years: 8 , Capacity: 78.4999. نطبع طول أطول سلسلة متتالية من القراءات فوق 40 درجة.run = 0
best = 0
t = int(input("Temp (999 stops): "))
while t != 999:
if t > 40:
run += 1
if run > best:
best = run
else:
run = 0
t = int(input("Temp (999 stops): "))
print("Longest hot run:", best)41, 45, 30, 42, 43, 44, 20, 999 يطبع: Longest hot run: 3a = int(input("LED A period: "))
b = int(input("LED B period: "))
t = a
while t % b != 0:
t += a
print("Together after:", t)4, 6 يطبع: Together after: 12goal = 5
best_err = 12
r1 = 100
while r1 <= 1000:
r2 = 100
while r2 <= 1000:
vout = 12 * r2 / (r1 + r2)
err = abs(vout - goal)
if err < best_err:
best_err = err
best1 = r1
best2 = r2
r2 += 100
r1 += 100
print("R1 =", best1, "R2 =", best2)
print("Error:", round(best_err, 3), "V")R1 = 700 R2 = 500 , Error: 0.0 V-1. لكل بايت نعدّ الخانات التي قيمتها 1 بالقسمة المتكررة على 2، ونطبع عددها وباقي قسمته على 2.value = int(input("Byte (-1 stops): "))
while value != -1:
ones = 0
rest = value
while rest > 0:
ones += rest % 2
rest = rest // 2
print(value, "ones:", ones, "parity:", ones % 2)
value = int(input("Byte (-1 stops): "))5, 7 يطبع: 5 ones: 2 parity: 0 , 7 ones: 3 parity: 1שאלות בגרות – أسئلة بجروت للفصل 4
| البند | المطلوب | الإجابة |
|---|---|---|
| السؤال كله | نعدّ طلبات القمصان والجرزايات حتى عدد غير قانوني، ثم نطبع العددين والمبلغ الكلي. | في الأسفل |
نبدأ بالترجمة: نتوقف عندما يختلف العدد عن 1 و2، أي نستمر ما دام يساوي 1 أو 2. العدد غير القانوني هو قيمة توقّف، لكن كل عدد آخر يصلح لذلك، ولهذا نكتب الشرط على القيم الصالحة. والعددان عدّادان مع شرط، أما المبلغ فنحسبه بعد الحلقة. نكتب البرنامج ونجرّبه على طلبات من عندنا:
shirts = 0
sweaters = 0
choice = int(input("1 shirt, 2 sweater: "))
while choice == 1 or choice == 2:
if choice == 1:
shirts += 1
else:
sweaters += 1
choice = int(input("1 shirt, 2 sweater: "))
total = shirts * 30 + sweaters * 50
print("Shirts:", shirts)
print("Sweaters:", sweaters)
print("Total:", total)1 shirt, 2 sweater: 1 1 shirt, 2 sweater: 2 1 shirt, 2 sweater: 1 1 shirt, 2 sweater: 1 1 shirt, 2 sweater: 2 1 shirt, 2 sweater: 7 Shirts: 3 Sweaters: 2 Total: 190
الأسماء shirts وsweaters بالإنجليزية كما تعوّدنا. ونفحص أيضا الحالة الحدّية: عدد غير قانوني من البداية، فيطبع البرنامج في السطر الأخير Total: 0.
| البند | المطلوب | الإجابة |
|---|---|---|
| السؤال كله | نقرأ رقم المرشّح ومبلغ التبرّع حتى يتحقّق شرط التوقف، ثم نطبع مجموع كل مرشّح، عدد المتبرّعين وأعلى تبرّع لكل مرشّح. | في الأسفل |
شرط الإنهاء مركب: يصل المجموع الكلي إلى مليون أو يصل عدد المتبرّعين إلى ألف، فنترجمه كما في البند 4.5:
| الشرط | |
|---|---|
| نتوقف عندما | sum1 + sum2 >= 1000000 or donors >= 1000 |
| نستمر ما دام | sum1 + sum2 < 1000000 and donors < 1000 |
ونحتاج إلى مُجمِّعين، عدّاد وقيمتين قصويين. يمكن أن تبدأ القيمتان القصويان من الصفر، لأن التبرّع مبلغ موجب، وهذا خلاف ما رأيناه مع الحرارة. ومع ألف تبرّع صغير تتوقف الحلقة بسبب عدد المتبرّعين، ويطبع البرنامج Donors: 1000. ونشغّله الآن على المثال الذي في نص السؤال:
sum1 = 0
sum2 = 0
max1 = 0
max2 = 0
donors = 0
while sum1 + sum2 < 1000000 and donors < 1000:
candidate = int(input("Candidate: "))
amount = float(input("Amount: "))
donors += 1
if candidate == 1:
sum1 += amount
if amount > max1:
max1 = amount
else:
sum2 += amount
if amount > max2:
max2 = amount
print("Candidate 1 sum:", sum1)
print("Candidate 2 sum:", sum2)
print("Donors:", donors)
print("Max Donation for Candidate 1:", max1)
print("Max Donation for Candidate 2:", max2)Candidate: 1 Amount: 200000 Candidate: 2 Amount: 300000 Candidate: 1 Amount: 100000 Candidate: 1 Amount: 100000 Candidate: 2 Amount: 200000 Candidate: 1 Amount: 150000 Candidate 1 sum: 550000.0 Candidate 2 sum: 500000.0 Donors: 6 Max Donation for Candidate 1: 200000.0 Max Donation for Candidate 2: 300000.0
الأعداد هي نفسها التي في السؤال. الفرق الوحيد هو .0 في نهايتها، لأن المبلغ عدد حقيقي حسب نص السؤال، فقرأناه بالدالة float. وتتوقف الحلقة بعد المتبرّع السادس، حين يصبح المجموع 1050000.