Περίληψη
Αυτό το μάθημα δεν περιέχει κώδικα, και όχι από αμέλεια: ο αλγόριθμος προηγείται του προγράμματος, και όποιος δεν ξέρει να περιγράψει με ακρίβεια τι πρέπει να γίνει δεν θα μπορέσει να το πει ούτε σε C++. Πρώτα διδάσκεται πώς προδιαγράφεται ένα πρόβλημα, δηλαδή πώς δηλώνεται ποια δεδομένα δέχεται, ποιο αποτέλεσμα πρέπει να δώσει και ποια σχέση τα συνδέει, και φαίνεται ότι η ίδια διατύπωση επιδέχεται διαφορετικές προδιαγραφές. Έπειτα ο αλγόριθμος ορίζεται ως διαδικασία πεπερασμένη, σαφής και γενική, και γράφεται σε αριθμημένα βήματα ο αλγόριθμος της διαίρεσης με διαδοχικές αφαιρέσεις. Διδάσκεται η εκτέλεση ενός αλγορίθμου με το χέρι με έναν πίνακα ίχνους, που σε όλο τον κύκλο μαθημάτων θα είναι το πρώτο εργαλείο για να κατανοούμε και για να αποσφαλματώνουμε. Παρουσιάζονται οι τρεις τρόποι συνδυασμού βημάτων (ακολουθία, απόφαση και επανάληψη), με τους οποίους γράφεται κάθε αλγόριθμος, και μαθαίνουμε να αιτιολογούμε ότι μια επανάληψη τερματίζει μέσω μιας ποσότητας που μειώνεται σε κάθε γύρο και δεν μπορεί να κατεβαίνει επ’ άπειρον.
Μαθησιακοί στόχοι
- Να προδιαγράφει κανείς ένα απλό πρόβλημα δηλώνοντας τις εισόδους του, τις εξόδους του και τις συνθήκες που πρέπει να ικανοποιούν.
- Να περιγράφει έναν αλγόριθμο σε αριθμημένα βήματα, χωρίς ασάφεια, με ρητές αποφάσεις και επαναλήψεις.
- Να εκτελεί με το χέρι έναν αλγόριθμο με έναν πίνακα ίχνους και να βρίσκει το αποτέλεσμά του για μια δεδομένη είσοδο.
- Να διακρίνει, σε μια δεδομένη διαδικασία, την ακολουθία, την απόφαση και την επανάληψη, και να αιτιολογεί ότι μια επανάληψη τερματίζει.
Τι είναι ένα υπολογιστικό πρόβλημα
Ένα υπολογιστικό πρόβλημα είναι μια σχέση ανάμεσα σε δύο κατηγορίες δεδομένων: αυτά που λαμβάνονται, που λέγονται είσοδος, και αυτά που πρέπει να δοθούν, που λέγονται έξοδος. Η επίλυσή του δεν συνίσταται στο να βρεθεί μια απάντηση για μία περίπτωση, αλλά στο να διαθέτουμε μια μέθοδο που, για κάθε αποδεκτή είσοδο, παράγει μια έξοδο που ικανοποιεί τη σχέση. «Πόσο κάνει το 17 διά 5;» είναι μια ερώτηση· «δεδομένων δύο ακεραίων, να βρεθούν το πηλίκο και το υπόλοιπό τους» είναι ένα πρόβλημα, επειδή μιλά για όλα τα ζεύγη ακεραίων ταυτόχρονα.
Η καθημερινή γλώσσα όμως είναι ανακριβής, και η ίδια διατύπωση μπορεί να κατανοηθεί με πολλούς τρόπους. Γι’ αυτό, πριν από την επίλυση, γίνεται προδιαγραφή: γράφεται τι μπαίνει, τι βγαίνει και ποιες συνθήκες πρέπει να ικανοποιεί το καθένα. Η προδιαγραφή έχει τρία μέρη. Η είσοδος απαριθμεί τα δεδομένα με το είδος τους (ακέραιοι, δεκαδικοί, λέξεις) και τις συνθήκες που απαιτούνται από αυτά, οι οποίες λέγονται προσυνθήκη: όποιος χρησιμοποιεί τη λύση δεσμεύεται να τις τηρεί. Η έξοδος απαριθμεί τα αποτελέσματα. Η σχέση, ή μετασυνθήκη, λέει τι πρέπει να ικανοποιεί η έξοδος σε σχέση με την είσοδο: όποιος γράφει τη λύση δεσμεύεται να την εξασφαλίζει εφόσον έχει τηρηθεί η προσυνθήκη. Από αυτό έπεται ότι η προδιαγραφή είναι μια σύμβαση ανάμεσα σε όποιον θέτει το πρόβλημα και σε όποιον το λύνει, και ότι έξω από την προσυνθήκη η λύση δεν υπόσχεται τίποτα.
Καθημερινή διατύπωση: «να βρεθεί ο μεγαλύτερος από τρεις αριθμούς». Προδιαγραφή:
- Είσοδος: τρεις αριθμοί , , (ακέραιοι ή δεκαδικοί, χωρίς άλλη συνθήκη).
- Έξοδος: ένας αριθμός .
- Σχέση: ο είναι ένα από τα τρία δεδομένα, και κανένα από αυτά δεν είναι μεγαλύτερο από τον · δηλαδή , και .
Η σχέση δεν λέει «ο μεγαλύτερος από τους τρεις», που είναι ακριβώς αυτό που θέλαμε να διευκρινίσουμε, αλλά δύο ελέγξιμες συνθήκες. Η πρώτη απαιτεί ο να είναι ένα από τα δεδομένα (χωρίς αυτήν, ο αριθμός 1000 θα ικανοποιούσε τη δεύτερη για σχεδόν οποιαδήποτε είσοδο)· η δεύτερη, να μην τον ξεπερνά κανένα. Και η προδιαγραφή λύνει παρεμπιπτόντως μια αμφιβολία που η διατύπωση άφηνε ανοιχτή: αν δύο δεδομένα ισοβαθμούν στο μέγιστο, όπως στο , η έξοδος είναι , και δεν υπάρχει κανένα σφάλμα σε αυτό.
Η ίδια διατύπωση επιδέχεται διαφορετικές προδιαγραφές, και η επιλογή ανάμεσά τους είναι απόφαση, όχι αμέλεια. Η πιο διδακτική περίπτωση είναι η ακέραια διαίρεση. Για ακεραίους και , όλοι συμφωνούν: το πηλίκο και το υπόλοιπο είναι οι μοναδικοί ακέραιοι που ικανοποιούν
Έτσι, για και είναι και , επειδή . Η διατύπωση «να διαιρεθούν δύο ακέραιοι» όμως δεν λέει τι γίνεται αν ο είναι αρνητικός, και το ερώτημα δεν είναι αδιάφορο: για και υπάρχουν δύο εύλογες απαντήσεις.
Πρώτη προδιαγραφή: το υπόλοιπο δεν είναι ποτέ αρνητικό, . Τότε , και η έξοδος είναι , . Αυτή μελετά η μαθηματική επιστήμη, στο μάθημα «Διαιρετότητα και διαίρεση με υπόλοιπο» του κύκλου μαθημάτων Άλγεβρα και γεωμετρία I.
Δεύτερη προδιαγραφή: το πηλίκο είναι το αποτέλεσμα της διαίρεσης με δεκαδικά, με το δεκαδικό του μέρος απορριμμένο, δηλαδή στρογγυλεμένο προς το μηδέν· το υπόλοιπο είναι ό,τι λείπει, και έχει το πρόσημο του διαιρετέου. Τότε το αποκόπτεται σε , και : η έξοδος είναι , .
Και οι δύο ικανοποιούν · διαφέρουν στη συνθήκη που επιβάλλεται στο υπόλοιπο. Καμία δεν είναι σφάλμα, αλλά ένα πρόγραμμα που χρησιμοποιεί τη μία νομίζοντας ότι χρησιμοποιεί την άλλη θα δίνει λάθος αποτελέσματα με τους αρνητικούς. Ας προλάβουμε ένα στοιχείο: η C++ υιοθετεί τη δεύτερη, όπως θα φανεί στο μάθημα Αριθμητικές πράξεις· όποιος περιμένει την πρώτη θα αιφνιδιαστεί.
Υπάρχει και τρίτη επιλογή, η συχνότερη στην πράξη: να αποκλειστεί η περίπτωση από την προσυνθήκη. Αν η προδιαγραφή απαιτεί , το πρόβλημα των αρνητικών εξαφανίζεται, όχι επειδή λύθηκε, αλλά επειδή όποιος χρησιμοποιεί τη λύση έχει δεσμευτεί να μην το θέσει. Αυτό που δεν μπορεί να γίνει είναι να μείνει το ζήτημα αναπάντητο. Και για τον ίδιο λόγο η προδιαγραφή απαιτεί : με δεν υπάρχουν και που να ικανοποιούν τη σχέση, και η σύμβαση πρέπει να το λέει.
Ένα συχνό σφάλμα είναι η προδιαγραφή με ένα παράδειγμα: «η έξοδος για 17 και 5 είναι 3 και 2». Ένα παράδειγμα φωτίζει, αλλά δεν προδιαγράφει, επειδή δεν λέει τι συμβαίνει με τις υπόλοιπες εισόδους· άπειρες διαφορετικές σχέσεις συμπίπτουν σε μία περίπτωση. Η προδιαγραφή γράφεται ως γενική συνθήκη, και τα παραδείγματα χρησιμεύουν έπειτα για να την ελέγξουμε.
Αλγόριθμοι
Αφού προδιαγραφεί το πρόβλημα, αναζητείται μια μέθοδος για να λυθεί. Ένας αλγόριθμος είναι μια ακολουθία εντολών που, εφαρμοσμένη σε οποιαδήποτε είσοδο ικανοποιεί την προσυνθήκη, παράγει σε πεπερασμένο αριθμό βημάτων μια έξοδο που ικανοποιεί τη μετασυνθήκη. Ο ορισμός περιέχει τρεις απαιτήσεις.
- Περατότητα. Ο αλγόριθμος γράφεται με πεπερασμένο αριθμό εντολών και, για κάθε αποδεκτή είσοδο, τερματίζει αφού εκτελέσει πεπερασμένο αριθμό από αυτές. Μια διαδικασία που για κάποια είσοδο συνεχίζει για πάντα δεν είναι αλγόριθμος για αυτή την είσοδο.
- Σαφήνεια. Κάθε εντολή έχει μία μόνο σημασία, και όποιος την εκτελεί ξέρει σε κάθε στιγμή τι να κάνει και ποια είναι η επόμενη εντολή. Καμία απόφαση δεν αφήνεται στην κρίση εκείνου που εκτελεί.
- Γενικότητα. Ο αλγόριθμος λύνει το πρόβλημα για όλες τις αποδεκτές εισόδους, όχι μόνο για μία περίπτωση.
Με κάποια ελευθερία, αλγόριθμος λέγεται και μια διαδικασία σαφής που τερματίζει, αλλά που για κάποια αποδεκτή είσοδο δεν ικανοποιεί τη μετασυνθήκη: αυστηρά είναι αλγόριθμος για άλλο πρόβλημα, και θα λέμε ότι είναι λανθασμένος για το προδιαγεγραμμένο πρόβλημα. Έτσι θα μιλάμε στα προβλήματα αυτού του μαθήματος, που ανασκευάζουν λανθασμένους αλγορίθμους με ένα αντιπαράδειγμα.
Μια συνταγή μαγειρικής μοιάζει με αλγόριθμο, και γι’ αυτό είναι η συνηθισμένη σύγκριση· σχεδόν καμία όμως δεν είναι. Το «προσθέτουμε μια πρέζα αλάτι» δεν είναι σαφές, επειδή μια πρέζα δεν είναι ποσότητα· το «ψήνουμε ώσπου να ροδίσει» εξαρτάται από μια κρίση που δύο άνθρωποι θα έκαναν διαφορετικά· το «χτυπάμε αρκετές φορές» δεν λέει πόσες. Ένας μάγειρας συμπληρώνει αυτά τα κενά με την πείρα του· ένας υπολογιστής δεν έχει καμία. Από αυτό έπεται η απαίτηση που διέπει όλο τον κύκλο μαθημάτων: έναν αλγόριθμο πρέπει να μπορεί να τον ακολουθήσει όποιος δεν καταλαβαίνει το πρόβλημα, χωρίς να μαντεύει τίποτα. Αν για να εκτελεστεί ένα βήμα πρέπει να ξέρει κανείς σε τι χρησιμεύει, το βήμα είναι κακογραμμένο.
Οι αλγόριθμοι αυτού του κύκλου μαθημάτων γράφονται πρώτα σε αριθμημένα βήματα, στα ελληνικά, με ορισμένες συμβάσεις. Τα δεδομένα που αλλάζουν κατά τη διάρκεια του αλγορίθμου ονομάζονται με γράμματα ή λέξεις, όπως ή , και λέγονται μεταβλητές. Γράφουμε «η παίρνει την τιμή » για να πούμε ότι υπολογίζεται η με την τρέχουσα τιμή της και το αποτέλεσμα γίνεται η νέα τιμή της · η προηγούμενη τιμή χάνεται. Στη σύντομη γραφή, που χρησιμοποιείται όταν κρατάμε σημειώσεις, η ίδια εντολή γράφεται με ένα βέλος προς τα αριστερά, που στο πληκτρολόγιο είναι r <- r - b. Οι εντολές εκτελούνται με τη σειρά του αριθμού τους, εκτός αν κάποια από αυτές ορίζει κάτι άλλο.
Το πρόβλημα είναι αυτό που προδιαγράφηκε στην προηγούμενη παράγραφο: είσοδος, δύο ακέραιοι και · έξοδος, δύο ακέραιοι και με και . Η ιδέα είναι η μοιρασιά: αφαιρούνται από τον ομάδες των όσο γίνεται, μετρώνται οι ομάδες που αφαιρέθηκαν, και ό,τι περισσεύει είναι το υπόλοιπο.
- Η παίρνει την τιμή , και η παίρνει την τιμή .
- Όσο ισχύει , επανάλαβε τα βήματα 3 και 4· όταν πάψει να ισχύει, συνέχισε στο βήμα 5.
- Η παίρνει την τιμή .
- Η παίρνει την τιμή · επίστρεψε στο βήμα 2.
- Δώσε ως αποτέλεσμα τις και , και τερμάτισε.
Το βήμα 2 είναι μια ερώτηση που γίνεται κάθε φορά: πριν από τον πρώτο γύρο και μετά από καθέναν. Τα βήματα 3 και 4 αποτελούν το σώμα της επανάληψης, αυτό που επαναλαμβάνεται. Τίποτα δεν αφήνεται στην κρίση εκείνου που εκτελεί: σε κάθε στιγμή υπάρχει μία μόνο επόμενη εντολή.
Ο αλγόριθμος είναι αργός (για να διαιρέσει ένα εκατομμύριο διά τρία κάνει πάνω από τριακόσιες χιλιάδες γύρους), και η σχολική μέθοδος της διαίρεσης είναι πολύ ταχύτερη· είναι όμως σωστός, και η απλότητά του τον κάνει ιδανικό για να μάθουμε να συλλογιζόμαστε πάνω στους αλγορίθμους. Ο κύκλος μαθημάτων θα επανέλθει στη διαφορά ανάμεσα σε έναν σωστό και έναν αποδοτικό αλγόριθμο στο μάθημα Το κόστος ενός αλγορίθμου.
Αξίζει, τέλος, να χωρίσουμε τον αλγόριθμο από τη γραφή του. Ο αλγόριθμος της διαίρεσης με αφαιρέσεις είναι ο ίδιος είτε γραφτεί στα ελληνικά, είτε σε διάγραμμα, είτε σε C++ ή σε οποιαδήποτε άλλη γλώσσα προγραμματισμού: αυτό που τον ορίζει είναι η ακολουθία των πράξεων, όχι οι λέξεις. Ένα πρόγραμμα είναι η γραφή ενός αλγορίθμου σε μια γλώσσα που μπορεί να εκτελέσει μια μηχανή, και το μάθημα Προγράμματα, μεταγλωττιστές και C++ θα εξηγήσει πώς γίνεται αυτή η εκτέλεση. Αν αυτό ισχύει, ένα πρόγραμμα μπορεί να είναι λάθος με δύο πολύ διαφορετικούς τρόπους: επειδή ο αλγόριθμος είναι λανθασμένος, και τότε καμία γλώσσα δεν τον σώζει, ή επειδή ο αλγόριθμος είναι σωστός αλλά γράφτηκε λάθος. Η διάκριση των δύο περιπτώσεων είναι η μισή δουλειά της αποσφαλμάτωσης, και γι’ αυτό ο κύκλος μαθημάτων γράφει πάντα πρώτα τον αλγόριθμο.
Εκτέλεση ενός αλγορίθμου με το χέρι
Η ανάγνωση ενός αλγορίθμου δεν αρκεί για να ξέρουμε τι κάνει· πρέπει να τον εκτελέσουμε. Η εκτέλεσή του με το χέρι, όπως θα τον εκτελούσε η μηχανή, χωρίς να παραλείπουμε βήματα ούτε να μαντεύουμε αποτελέσματα, είναι η πιο χρήσιμη δεξιότητα όποιου προγραμματίζει: με αυτήν ελέγχεται ένας αλγόριθμος πριν γραφτεί, προβλέπεται η έξοδος ενός προγράμματος πριν εκτελεστεί και εντοπίζεται το σφάλμα ενός προγράμματος που αποτυγχάνει.
Το εργαλείο είναι ο πίνακας ίχνους: μία στήλη για τον αριθμό του βήματος που εκτελείται, μία στήλη ανά μεταβλητή και, αν χρειάζεται, μία για τις συνθήκες που αποτιμώνται· και μία γραμμή για κάθε βήμα που εκτελείται. Σε κάθε γραμμή σημειώνεται η νέα τιμή της μεταβλητής που άλλαξε σε εκείνο το βήμα και αφήνεται κενό ό,τι δεν άλλαξε, ώστε η τρέχουσα τιμή μιας μεταβλητής να είναι η τελευταία γραμμένη στη στήλη της. Οι συνθήκες σημειώνονται με το αποτέλεσμά τους.
Εκτελούμε τη διαίρεση με διαδοχικές αφαιρέσεις με και . Το βέλος του σχήματος δείχνει το βήμα που μόλις εκτελέστηκε· η διακεκομμένη γραμμή θυμίζει ότι το βήμα 4 επιστρέφει στο 2.
Απόδειξη
Βήμα 1: δίνονται οι αρχικές τιμές. Η είσοδος ικανοποιεί την προσυνθήκη, επειδή και .
Πρώτος γύρος. Στο βήμα 2 ελέγχεται ότι , οπότε εκτελείται το σώμα: το βήμα 3 αφαιρεί μια ομάδα των πέντε και το βήμα 4 τη μετρά.
Δεύτερος γύρος: , και το σώμα εκτελείται ξανά.
Τρίτος γύρος: , και το σώμα εκτελείται ξανά.
Στο βήμα 2 η συνθήκη αποτυγχάνει, επειδή : ο αλγόριθμος συνεχίζει στο βήμα 5 και δίνει και . Η έξοδος ικανοποιεί τη μετασυνθήκη.
Ο πλήρης πίνακας έχει δώδεκα γραμμές: το βήμα 1, τρεις γύρους των τριών γραμμών ο καθένας (βήματα 2, 3 και 4), τον έλεγχο που αποτυγχάνει και την απόδοση του αποτελέσματος.
Δύο παρατηρήσεις για τον πίνακα. Η πρώτη: ο αριθμός των γύρων είναι ίσος με το πηλίκο, , και το βήμα 2 εκτελέστηκε μία φορά περισσότερο από το σώμα, φορές· αυτό συμβαίνει πάντα σε μια επανάληψη αυτής της μορφής, επειδή ο τελευταίος έλεγχος είναι αυτός που αποτυγχάνει. Η δεύτερη: το ίχνος δείχνει κάτι που το κείμενο του αλγορίθμου δεν λέει με την πρώτη ματιά· αν , για παράδειγμα και , η συνθήκη αποτυγχάνει την πρώτη φορά, το σώμα δεν εκτελείται καμία φορά, και η έξοδος είναι , , που είναι σωστή, επειδή . Η παράλειψη της περίπτωσης όπου η επανάληψη δεν εκτελείται είναι ένα από τα συχνότερα σφάλματα στη σχεδίαση αλγορίθμων, και το ίχνος με μικρές εισόδους την αποκαλύπτει.
Το ίχνος μιας περίπτωσης δεν αποδεικνύει ότι ο αλγόριθμος είναι σωστός: ελέγχει μία περίπτωση. Ένα καλά διαλεγμένο ίχνος όμως (μια συνηθισμένη περίπτωση, μια οριακή περίπτωση, η περίπτωση όπου η επανάληψη δεν εκτελείται) αποκαλύπτει τα περισσότερα σφάλματα, και εκείνο που αποτυγχάνει δείχνει πού βρίσκονται. Το μάθημα Σχεδίαση σωστών βρόχων θα διδάξει πώς περνάμε από τις περιπτώσεις σε μια απόδειξη.
Ακολουθία, απόφαση και επανάληψη
Αν τους κοιτάξουμε από κοντά, οι αλγόριθμοι κατασκευάζονται με πολύ λίγα κομμάτια. Υπάρχουν στοιχειώδεις εντολές (να δοθεί τιμή σε μια μεταβλητή, να δοθεί ένα αποτέλεσμα) και τρεις τρόποι να συνδυαστούν.
- Ακολουθία: μια εντολή μετά από την άλλη, με τη σειρά. Τα βήματα 3 και 4 της διαίρεσης είναι μια ακολουθία: πρώτα αφαιρούμε, έπειτα μετράμε.
- Απόφαση: ανάλογα με το αν ισχύει ή όχι μια συνθήκη, εκτελείται ένα μέρος ή ένα άλλο (ή ένα μέρος ή τίποτα). Το «Αν , η παίρνει την τιμή » είναι μια απόφαση.
- Επανάληψη: όσο ισχύει μια συνθήκη, εκτελείται ένα μέρος ξανά και ξανά. Το βήμα 2 της διαίρεσης, με το σώμα του, είναι μια επανάληψη.
Κάθε μορφή έχει μία μόνο είσοδο και μία μόνο έξοδο, και το εσωτερικό της μπορεί να είναι με τη σειρά του οποιαδήποτε από τις τρεις: το σώμα μιας επανάληψης μπορεί να περιέχει αποφάσεις, ένας κλάδος μιας απόφασης μπορεί να περιέχει μια επανάληψη, και ούτω καθεξής. Αν αυτό ισχύει, με τις τρεις μορφές κατασκευάζονται αλγόριθμοι οποιασδήποτε πολυπλοκότητας, όπως με λίγα κομμάτια που ταιριάζουν μεταξύ τους κατασκευάζεται οποιοδήποτε οικοδόμημα. Ότι αρκούν για να εκφραστεί κάθε αλγόριθμος είναι ένα γνωστό αποτέλεσμα της θεωρίας του προγραμματισμού (το απέδειξαν οι Κοράντο Μπεμ και Τζουζέπε Τζακοπίνι το 1966)· εδώ δεν αποδεικνύεται, αλλά όλος ο κύκλος μαθημάτων το επιβεβαιώνει: τα προγράμματα που θα γραφτούν σε αυτόν, όσο μεγάλα κι αν είναι, δεν θα χρησιμοποιούν τίποτε άλλο από αυτές τις τρεις μορφές, γραμμένες σε C++ ως if για την απόφαση και while ή for για την επανάληψη, στα μαθήματα Αποφάσεις και Βρόχοι.
Ένας χρήσιμος συμβολισμός για να βλέπουμε τη μορφή ενός αλγορίθμου είναι το διάγραμμα ροής: κάθε εντολή είναι ένα ορθογώνιο, κάθε συνθήκη ένας ρόμβος με δύο εξόδους (ικανοποιείται, που το σχήμα σημειώνει με , και δεν ικανοποιείται, ), και τα βέλη λένε ποιο είναι το επόμενο βήμα. Είναι συμβολισμός, όχι σκοπός: χρησιμεύει για να δούμε έναν μικρό αλγόριθμο με μια ματιά, αλλά δεν κλιμακώνεται, και κανείς δεν γράφει ένα μεγάλο πρόγραμμα σχεδιάζοντάς το.
Το σχήμα σχεδιάζει τις τρεις μορφές με γενικές εντολές και και μια συνθήκη , και έπειτα τις συνθέτει στο διάγραμμα της διαίρεσης με διαδοχικές αφαιρέσεις.
Απόδειξη
Ακολουθία: εκτελείται η και έπειτα η · υπάρχει μία μόνο είσοδος και μία μόνο έξοδος.
Απόφαση: αν η ικανοποιείται, εκτελείται η · αλλιώς, η . Οι δύο κλάδοι ενώνονται σε μία μόνο έξοδο.
Επανάληψη: αποτιμάται η · αν ικανοποιείται, εκτελείται η και αποτιμάται ξανά η · αλλιώς, βγαίνουμε. Η συνθήκη αποτιμάται μία φορά περισσότερο από το σώμα.
Σύνθεση: η διαίρεση με διαδοχικές αφαιρέσεις είναι μια ακολουθία (οι αρχικές τιμές, η επανάληψη, η απόδοση του αποτελέσματος) της οποίας η επανάληψη έχει ως σώμα μια άλλη ακολουθία (αφαίρεση, μέτρηση).
Η διάκριση των τριών μορφών σε μια διαδικασία γραμμένη στην καθημερινή γλώσσα είναι το πρώτο βήμα για να μεταφραστεί. Το σήμα μιας απόφασης είναι ένα «αν», ένα «σε περίπτωση που» ή ένα «ανάλογα με»· μιας επανάληψης, ένα «όσο», ένα «ώσπου», ένα «για κάθε» ή ένα «τόσες φορές όσες». Μια διαδικασία χωρίς καμία από αυτές τις λέξεις είναι ακολουθία, και αν πρέπει να χειριστεί εισόδους μεταβλητού μεγέθους (μια λίστα αριθμών, ένα κείμενο), της λείπει μια επανάληψη.
Τερματίζει;
Η περατότητα είναι μέρος του ορισμού του αλγορίθμου, και η επανάληψη είναι το μόνο σημείο όπου μπορεί να χαθεί: μια ακολουθία πέντε βημάτων εκτελεί πέντε βήματα, και μια απόφαση εκτελεί έναν από τους κλάδους της· μια επανάληψη όμως εκτελεί το σώμα της τόσες φορές όσες ικανοποιείται η συνθήκη, και τίποτα δεν εγγυάται εκ των προτέρων ότι θα πάψει να ικανοποιείται.
Για να αιτιολογήσουμε ότι μια επανάληψη τερματίζει, αναζητούμε μια ποσότητα, υπολογισμένη από τις μεταβλητές, που να ικανοποιεί δύο συνθήκες: είναι φυσικός αριθμός (ακέραιος και μη αρνητικός) όσο η επανάληψη συνεχίζεται, και φθίνει γνησίως σε κάθε γύρο. Αν αυτό ισχύει, η επανάληψη τερματίζει: μια γνησίως φθίνουσα ακολουθία φυσικών δεν μπορεί να είναι άπειρη, επειδή κάθε γύρος την κατεβάζει τουλάχιστον κατά ένα και από έναν φυσικό δεν υπάρχουν περισσότερα από σκαλοπάτια ως το μηδέν. Αυτή η ποσότητα λέγεται φθίνουσα ποσότητα (variant) ή συνάρτηση φραγής, και το μάθημα Σχεδίαση σωστών βρόχων θα τη χρησιμοποιήσει συστηματικά.
Στη διαίρεση με διαδοχικές αφαιρέσεις, η φθίνουσα ποσότητα είναι η . Όσο η επανάληψη συνεχίζεται, , οπότε η είναι φυσικός. Σε κάθε γύρο, η παίρνει την τιμή , και επειδή (προσυνθήκη), η νέα τιμή είναι γνησίως μικρότερη. Επομένως η επανάληψη τερματίζει, και το κάνει το πολύ μετά από γύρους (στην πραγματικότητα, ακριβώς μετά από γύρους, όσο το πηλίκο).
Παρατηρήστε πού χρησιμοποιήθηκε η προσυνθήκη . Αν ο αλγόριθμος εκτελεστεί με , το βήμα 3 αφήνει την ίδια, η συνθήκη ικανοποιείται πάντα και η επανάληψη δεν τερματίζει ποτέ: ο αλγόριθμος δεν είναι λάθος, αλλά του δόθηκε μια είσοδος που η σύμβαση απέκλειε. Και αν ο ήταν αρνητικός, η θα αυξανόταν σε κάθε γύρο. Η προσυνθήκη δεν είναι στολίδι: είναι ακριβώς αυτό που χρειάζεται για να λειτουργήσει ο συλλογισμός.
Οι δύο συνθήκες της φθίνουσας ποσότητας είναι αναγκαίες, και είναι εύκολο να κάνει κανείς λάθος με οποιαδήποτε από αυτές. Ας θεωρήσουμε αυτή τη διαδικασία, που επιδιώκει να αποφασίσει αν ένας φυσικός είναι άρτιος: «όσο , ο παίρνει την τιμή · αν φτάσουμε στο μηδέν, ο ήταν άρτιος». Η ποσότητα μειώνεται σε κάθε γύρο, και παρ’ όλα αυτά η διαδικασία δεν τερματίζει αν ο είναι περιττός: με περνά από τα , , , , και η συνθήκη δεν αποτυγχάνει ποτέ. Αυτό που δεν ικανοποιείται είναι η άλλη συνθήκη: ο παύει να είναι φυσικός, επειδή η συνθήκη της επανάληψης δεν τον εμποδίζει να κατέβει κάτω από το μηδέν. Η διόρθωση είναι να επαναλαμβάνουμε όσο και να αποφασίζουμε στο τέλος ανάλογα με την τιμή που μένει, ή · τώρα ο είναι φυσικός σε κάθε γύρο, επειδή αφαιρούμε μόνο όταν , και μειώνεται: η διαδικασία τερματίζει.
Το να αποφασίσει κανείς αν μια επανάληψη τερματίζει δεν είναι πάντα εύκολο. Ένα διάσημο παράδειγμα: ξεκινώντας από έναν φυσικό , όσο , αν ο είναι άρτιος διαιρείται διά δύο, και αν είναι περιττός αντικαθίσταται από τον . Με η ακολουθία είναι , και τερματίζει. Κανείς δεν έχει βρει έναν για τον οποίο να μην τερματίζει, και έχει ελεγχθεί με υπολογιστές για τεράστιες ποσότητες τιμών· κανείς όμως δεν έχει καταφέρει να αποδείξει ότι τερματίζει πάντα: είναι η εικασία του Κόλατζ, ένα ανοιχτό πρόβλημα των μαθηματικών. Καμία γνωστή ποσότητα δεν μειώνεται σε κάθε γύρο. Το δίδαγμα για όποιον προγραμματίζει είναι μετριοπαθές και σταθερό: ένας αλγόριθμος του οποίου τον τερματισμό δεν ξέρουμε να αιτιολογήσουμε δεν έχει τελειώσει.
Συχνά σφάλματα
- Ασαφή βήματα. «Επανάλαβε αρκετές φορές», «ώσπου να είναι εντάξει», «πάρε έναν κατάλληλο αριθμό». Κάθε βήμα πρέπει να μπορεί να εκτελεστεί χωρίς να γίνει κατανοητό το πρόβλημα· αλλιώς, είναι κακογραμμένο.
- Παράλειψη της περίπτωσης όπου η επανάληψη δεν εκτελείται. Κάθε επανάληψη με τη συνθήκη στην αρχή μπορεί να εκτελέσει το σώμα της μηδέν φορές. Πρέπει πάντα να αναρωτιόμαστε τι δίνει ο αλγόριθμος σε αυτή την περίπτωση, και το ίχνος με μια ελάχιστη είσοδο το απαντά.
- Προδιαγραφή με ένα παράδειγμα. Το «για 17 και 5 δίνει 3 και 2» δεν είναι προδιαγραφή· η σχέση γράφεται ως γενική συνθήκη, και το παράδειγμα τη φωτίζει.
- Σύγχυση του αλγορίθμου με το πρόγραμμά του. Ένα πρόγραμμα που αποτυγχάνει μπορεί να έχει λάθος τον αλγόριθμο ή λάθος τη γραφή του. Όποιος δεν έγραψε πρώτα τον αλγόριθμο δεν ξέρει ποιο από τα δύο να αναζητήσει.
- Ο τερματισμός θεωρείται δεδομένος. Δεν αρκεί να μειώνεται μια ποσότητα: πρέπει επιπλέον να είναι φυσικός αριθμός όσο συνεχίζεται η επανάληψη.
Λυμένα προβλήματα
Να γραφτεί ένας αλγόριθμος που ικανοποιεί την προδιαγραφή του μεγίστου τριών αριθμών της πρώτης παραγράφου, και να εκτελεστεί με το χέρι για τις εισόδους και .
Λύση
Ιδέα: διατρέχουμε την είσοδο κρατώντας τον μεγαλύτερο που έχουμε δει ως τώρα σε μια μεταβλητή . Πρώτο βήμα: η παίρνει την τιμή . Μετά από αυτό, η είναι το μέγιστο των δεδομένων που έχουμε δει, που είναι μόνο το .
Δεύτερο βήμα: αν , η παίρνει την τιμή . Τρίτο βήμα: αν , η παίρνει την τιμή . Τέταρτο βήμα: δώσε ως αποτέλεσμα την . Είναι τρεις εντολές σε ακολουθία, οι δύο από αυτές αποφάσεις χωρίς εναλλακτικό κλάδο.
Ίχνος για : μετά το πρώτο βήμα · στο δεύτερο, το είναι ψευδές και η δεν αλλάζει· στο τρίτο, το είναι ψευδές και η δεν αλλάζει. Δίνεται το .
Ίχνος για : μετά το πρώτο βήμα · στο δεύτερο, και η παίρνει την τιμή · στο τρίτο, το είναι ψευδές και η δεν αλλάζει. Δίνεται το , που είναι σωστό: η ισοβαθμία δεν χρειάζεται ιδιαίτερο χειρισμό.
Αιτιολόγηση: μετά από κάθε βήμα, η είναι ένα από τα δεδομένα που έχουμε δει και κανένα από αυτά δεν την ξεπερνά. Ισχύει μετά το πρώτο, και κάθε απόφαση το διατηρεί: αν το νέο δεδομένο είναι μεγαλύτερο, γίνεται η νέα · αλλιώς, δεν ξεπερνά την . Στο τέλος έχουμε δει και τα τρία, και η ικανοποιεί τη μετασυνθήκη.
Αν είχε γραφτεί αντί για , το αποτέλεσμα θα ήταν το ίδιο, επειδή σε περίπτωση ισοβαθμίας εκχωρείται ίση τιμή. Η επιλογή ανάμεσα σε και θα είχε σημασία αν ζητούνταν επιπλέον η θέση του μεγίστου: με δίνεται η πρώτη από τις ισοβαθμούσες θέσεις, και με η τελευταία, που ο τύπος ονομάζει .
Στο γρηγοριανό ημερολόγιο, ένα έτος είναι δίσεκτο αν διαιρείται με το , εκτός από όσα διαιρούνται με το , που είναι δίσεκτα μόνο αν διαιρούνται επιπλέον με το . Ένας φοιτητής προτείνει τον αλγόριθμο «αν το έτος διαιρείται με το , δώσε ναι· αλλιώς, δώσε όχι». Να βρεθεί ένα έτος στο οποίο αποτυγχάνει και να γραφτεί ένας σωστός αλγόριθμος, με την προδιαγραφή του.
Λύση
Προδιαγραφή. Είσοδος: ένας ακέραιος (το γρηγοριανό ημερολόγιο ισχύει από τον Οκτώβριο του 1582). Έξοδος: ναι ή όχι. Σχέση: η έξοδος είναι ναι ακριβώς όταν ο διαιρείται με το και όχι με το , ή διαιρείται με το .
Ο προτεινόμενος αλγόριθμος πετυχαίνει στα περισσότερα έτη, και γι’ αυτό φαίνεται σωστός. Για να ανασκευαστεί αρκεί ένα έτος που διαιρείται με το και όχι με το : το διαιρείται με το , και ο αλγόριθμος λέει ναι· το όμως δεν ήταν δίσεκτο.
Διορθωμένος αλγόριθμος, σε τρεις αλυσιδωτές αποφάσεις. Βήμα 1: αν ο διαιρείται με το , δώσε ναι και τερμάτισε. Βήμα 2: αν ο διαιρείται με το , δώσε όχι και τερμάτισε. Βήμα 3: αν ο διαιρείται με το , δώσε ναι· αλλιώς, δώσε όχι.
Η σειρά των ερωτήσεων είναι ουσιώδης: πηγαίνουν από τον πιο ειδικό κανόνα στον πιο γενικό. Αν ρωτούσαμε πρώτα για το , το έτος θα έπαιρνε ναι πριν φτάσει στην εξαίρεση. Ίχνος για τέσσερα έτη, ένα από κάθε περίπτωση: (βήμα 1: ναι), (βήμα 2: όχι), (βήμα 3: ναι), (βήμα 3: όχι).
Το δίδαγμα δεν αφορά μόνο τα ημερολόγια: ένας αλγόριθμος ανασκευάζεται με ένα μόνο αντιπαράδειγμα, και τα αντιπαραδείγματα αναζητούνται στα όρια των κανόνων, όχι στις συνηθισμένες περιπτώσεις. Οι δοκιμές με , και δεν θα είχαν αποκαλύψει τίποτα.
Να εκτελεστεί με το χέρι η διαίρεση με διαδοχικές αφαιρέσεις με και , και με και . Έπειτα, να αιτιολογηθεί ότι για κάθε αποδεκτή είσοδο ο αλγόριθμος τερματίζει μετά από ακριβώς γύρους και ότι η έξοδός του ικανοποιεί τη μετασυνθήκη.
Λύση
Ίχνος με , : η περνά από τα , , , , , και η από τα , , , , . Ο πέμπτος έλεγχος, , αποτυγχάνει. Έξοδος: , . Εδώ η οριακή περίπτωση είναι η ακριβής διαίρεση: ο τέταρτος γύρος γίνεται επειδή , και γι’ αυτό η συνθήκη πρέπει να είναι και όχι .
Ίχνος με , : ο πρώτος έλεγχος, , αποτυγχάνει· το σώμα δεν εκτελείται καμία φορά. Έξοδος: , , που είναι σωστή.
Μια σχέση που διατηρείται. Πριν από τον πρώτο γύρο, . Σε κάθε γύρο η μειώνεται κατά και η αυξάνεται κατά , οπότε η ποσότητα δεν αλλάζει. Επομένως η ισότητα ισχύει μετά από κάθε γύρο.
Τερματισμός. Όσο συνεχίζεται η επανάληψη, , και η είναι φυσικός· σε κάθε γύρο μειώνεται κατά . Μια γνησίως φθίνουσα ακολουθία φυσικών είναι πεπερασμένη: η επανάληψη τερματίζει.
Στο τέλος, η συνθήκη απέτυχε: . Επιπλέον , επειδή αφαιρείται ο μόνο όταν . Μαζί με τη σχέση που διατηρείται, η έξοδος ικανοποιεί τη μετασυνθήκη· και επειδή η μετρά τους γύρους, ο αριθμός των γύρων είναι το πηλίκο.
Ασκήσεις στο διαδίκτυο
Να εκτελεστεί με το χέρι ο παρακάτω αλγόριθμος και να γραφτεί στο πλαίσιο η τιμή που δίνει, μόνο ο αριθμός.
- Ο παίρνει την τιμή , και ο παίρνει την τιμή .
- Όσο ισχύει , επανάλαβε τα βήματα 3 και 4· όταν πάψει να ισχύει, συνέχισε στο βήμα 5.
- Αν ο είναι άρτιος, ο παίρνει την τιμή · αν είναι περιττός, ο παίρνει την τιμή .
- Ο παίρνει την τιμή · επίστρεψε στο βήμα 2.
- Δώσε ως αποτέλεσμα τον .
Το πρόγραμμα περιήγησης ελέγχει την απάντησή σου αμέσως, χωρίς να τη βαθμολογεί.
Υπόδειξη
Φτιάξε τον πίνακα: ο περνά από το στο στον πρώτο γύρο. Μέτρα έναν γύρο για κάθε αλλαγή του , ώσπου ο να γίνει .
Δες τη λύση
7Ο παρακάτω αλγόριθμος, γραμμένος στη σύντομη μορφή, πρέπει να υπολογίζει το πηλίκο και το υπόλοιπο της διαίρεσης με διαδοχικές αφαιρέσεις, αλλά του λείπει η συνθήκη της επανάληψης. Να αντικατασταθεί η γραμμή με τις κάτω παύλες από τη σωστή συνθήκη, χωρίς να αλλάξει τίποτε άλλο.
Το πρόγραμμα περιήγησης ελέγχει την απάντησή σου αμέσως, χωρίς να τη βαθμολογεί.
Υπόδειξη
Εκτέλεσε με το χέρι τον αλγόριθμο με και : ο δεύτερος γύρος πρέπει να γίνει, παρότι το υπόλοιπο είναι ακριβώς .
Δες τη λύση
Είσοδος: a (ακέραιος, a >= 0), b (ακέραιος, b > 0)1. q <- 02. r <- a3. όσο r >= b επανάλαβε: r <- r - b q <- q + 14. δώσε q, rΠροτεινόμενα προβλήματα
Κάθε πρόβλημα έχει μια υπόδειξη, που καλό είναι να ανοίγεται μόνο αφού επιχειρηθεί η λύση, και μια απάντηση, που εμφανίζεται αφού ανοιχτεί η υπόδειξη.
Να γραφτεί η προδιαγραφή του προβλήματος «να διαταχθούν τρεις αριθμοί» (είσοδος, έξοδος και σχέση) και να επισημανθεί ποιες αποφάσεις υποχρεώνει να ληφθούν, που η διατύπωση δεν έπαιρνε. Έπειτα, να ελεγχθεί ότι η προδιαγραφή απορρίπτει αυτές τις δύο εξόδους για την είσοδο : και , και ότι δέχεται την .
Υπόδειξη
Μια «διατεταγμένη» έξοδος μπορεί να μην έχει καμία σχέση με την είσοδο. Ποια συνθήκη συνδέει τους αριθμούς της εξόδου με εκείνους της εισόδου, μαζί με τους επαναλαμβανόμενους; Αύξουσα ή φθίνουσα; Γνήσια ή όχι;
Απάντηση
Είσοδος: τρεις αριθμοί , , . Έξοδος: τρεις αριθμοί , , . Σχέση: , και η είναι αναδιάταξη της , δηλαδή περιέχει τις ίδιες τιμές με τις ίδιες επαναλήψεις. Αποφάσεις που η διατύπωση δεν έπαιρνε: η φορά (εδώ, από τον μικρότερο στον μεγαλύτερο)· ότι η διάταξη δεν είναι γνήσια ( και όχι , επειδή με επαναλαμβανόμενες τιμές η γνήσια διάταξη είναι αδύνατη)· και ότι η έξοδος πρέπει να είναι αναδιάταξη. Η είναι διατεταγμένη αλλά περιέχει ένα που δεν υπήρχε· η έχει τέσσερις τιμές· η ικανοποιεί και τις δύο συνθήκες. Χωρίς τη συνθήκη της αναδιάταξης, η θα ήταν σωστή έξοδος για οποιαδήποτε είσοδο.
Να γραφτεί ένας αλγόριθμος σε αριθμημένα βήματα που δέχεται έναν φυσικό και δίνει τα ψηφία του από το τελευταίο ως το πρώτο (για το , δίνει , , , ), χρησιμοποιώντας μόνο το πηλίκο και το υπόλοιπο της διαίρεσης με το . Να εκτελεστεί με το χέρι για το και για το , και να αιτιολογηθεί ότι τερματίζει για κάθε .
Υπόδειξη
Το υπόλοιπο της διαίρεσης με το είναι το τελευταίο ψηφίο, και το πηλίκο είναι ο αριθμός χωρίς αυτό. Αποφάσισε αν η συνθήκη ελέγχεται πριν ή μετά από την απόδοση ενός ψηφίου, και δες τι συμβαίνει με , που έχει ένα ψηφίο.
Απάντηση
Ένας σωστός αλγόριθμος: (1) δώσε το υπόλοιπο της διαίρεσης του με το · (2) ο παίρνει την τιμή του πηλίκου της διαίρεσης του με το · (3) αν , επίστρεψε στο βήμα 1· αλλιώς, τερμάτισε. Η ερώτηση μπαίνει μετά από το σώμα, οπότε το σώμα εκτελείται τουλάχιστον μία φορά: για δίνει , που είναι το μοναδικό του ψηφίο. Αν η ερώτηση γινόταν στην αρχή («όσο »), για δεν θα δινόταν τίποτα· είναι το σφάλμα της παράλειψης της περίπτωσης όπου η επανάληψη δεν εκτελείται. Ίχνος για το : δίνονται τα , , , , και ο περνά από τα , , , . Τερματισμός: η φθίνουσα ποσότητα είναι ο , ένας φυσικός· αν επιστρέφουμε στο βήμα 1 είναι επειδή , και για το πηλίκο διά είναι γνησίως μικρότερο από τον , οπότε ο μειώνεται γνησίως σε κάθε γύρο.
Διαθέτουμε κέρματα των , και μονάδων, σε απεριόριστη ποσότητα. Προδιαγραφή: είσοδος, ένας φυσικός · έξοδος, τρεις φυσικοί , , με και τον μικρότερο δυνατό αριθμό κερμάτων, . Κάποιος προτείνει τον παρακάτω αλγόριθμο. Να βρεθεί μια είσοδος στην οποία αποτυγχάνει, να εξηγηθεί κάθε ελάττωμα και να διορθωθεί.
- Οι , και παίρνουν την τιμή .
- Αν , ο παίρνει την τιμή και ο παίρνει την τιμή .
- Όσο : ο παίρνει την τιμή και ο παίρνει την τιμή .
- Όσο : ο παίρνει την τιμή και ο παίρνει την τιμή .
- Δώσε ως αποτέλεσμα τους , και .
Υπόδειξη
Το άθροισμα των κερμάτων είναι πάντα · αυτό που μπορεί να αποτύχει είναι το πλήθος τους. Δοκίμασε ένα ακριβές πολλαπλάσιο του και ένα ποσό μεγαλύτερο από , και αναρωτήσου ποιον τρόπο συνδυασμού βημάτων χρησιμοποιεί το βήμα 2 και ποιον θα έπρεπε να χρησιμοποιεί.
Απάντηση
Υπάρχουν δύο ελαττώματα. Πρώτον, το βήμα 3 χρησιμοποιεί : με δεν δίνει κανένα κέρμα των και δίνει δέκα των , αντί για ένα. Δεύτερον, το βήμα 2 είναι απόφαση εκεί όπου χρειάζεται επανάληψη: με , ο αλγόριθμος όπως είναι γραμμένος δίνει ένα κέρμα των , έξι των και δέκα των (δεκαεπτά κέρματα), και ακόμη και με το βήμα 3 διορθωμένο θα έδινε ένα των και επτά των (οκτώ), αντί για δύο των και δύο των (τέσσερα). Η είσοδος δείχνει και τα δύο ελαττώματα: ο αλγόριθμος δίνει ένα των , τέσσερα των και δέκα των , δεκαπέντε κέρματα, αντί για δύο. Διόρθωση: βήμα 2, «όσο , …»· βήμα 3, «όσο , …». Έτσι διορθωμένος, ο αλγόριθμος παίρνει πάντα το μεγαλύτερο κέρμα που χωρά, και με αυτά τα τρία κέρματα αυτό δίνει το μικρότερο πλήθος: το ψηφίο των μονάδων του μπορεί να πληρωθεί μόνο με κέρματα του , και από ό,τι μένει συμφέρει να πληρωθεί με κέρματα των όσο το δυνατόν περισσότερο, επειδή πέντε των αξίζουν όσο ένα των . Με άλλα κέρματα, για παράδειγμα των , και για , η επιλογή πάντα του μεγαλύτερου δεν δίνει πια το ελάχιστο ( έναντι ).
Ολοκληρώθηκε
Συνδεθείτε για να αποθηκεύσετε την πρόοδό σας