Ακρίβεια πραγματικών αριθμών

Ξεκίνησε από alkisg, 07 Απρ 2020, 09:36:19 ΠΜ

« προηγούμενο - επόμενο »

alkisg

Πάμε στην Python ή σε οποιαδήποτε άλλη γλώσσα και γράφουμε:
print(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 1)

Απαντάει "False". Δηλαδή αν προσθέσουμε δέκα φορές το 0.1, δεν μας κάνει 1, αλλά 0.999999999.
Αυτό δημιουργεί προβλήματα σε συγκρίσεις, σε ΓΙΑ που χρησιμοποιούν πραγματικούς αριθμούς οι οποίες εκτελούνται μια φορά λιγότερη ή περισσότερη κλπ.
Ο Διερμηνευτής λύνει αυτό το πρόβλημα περιορίζοντας την ακρίβεια των συγκρίσεων, οπότε θεωρεί ότι 0.999999999 είναι ίσο με 1 και όλα καλά.

Η ερώτηση μου είναι: καλά κάνει ο Διερμηνευτής και κρύβει αυτό το θέμα από τους μαθητές, ή θα προτιμούσαμε να φαίνεται, όπως και στις πραγματικές γλώσσες προγραμματισμού;

dski

Προσωπική μου γνώμη ότι αυτού του είδους οι λεπτομέρειες καλώς δεν φτάνουν στους μαθητές. Ένας φοιτητής και μελλοντικός επαγγελματίας φυσικά θα πρέπει να γνωρίζει αυτά τα θέματα όμως οι μαθητές, οι οποίο μετά βίας έχουν ακούσει κάποια πράγματα για δυαδικό σύστημα και δυαδικές αναπαραστάσεις στο γυμνάσιο, δεν έχουν το υπόβαθρο να μπουν σε τέτοιες λεπτομέρειες. Επιπλέον οι μαθητές εξετάζονται στο χαρτί οπότε εκεί δεν νομίζω ότι κανείς μπορεί να τους προσάψει λάθος ότι 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 ίσως και να μην κάνει 1 όταν εκτελεστεί στον Η/Υ...

Τέλος, πέρα από όλα αυτά, νομίζω ότι κάτι τέτοιο ξεφεύγει και από τους σκοπούς του μαθήματος. Ναι, συζητάμε ότι ίσως είναι καλό να φύγουμε πλέον από τη Γλώσσα και να πάμε σε μια πραγματική γλώσσα προγραμματισμού όπως η Python αλλά μην ξεχνάμε ότι στόχος είναι να μάθουν οι μαθητές βασικές αρχές ανάλυσης προβλήματος, αλγορίθμων, προγραμματισμού κτλ. Συχνά δυσκολεύονται ακόμα και με απλούστερες βασικές έννοιες, δεν νομίζω ότι θα τους ωφελήσει καλό να μπουν και σε τέτοιες λεπτομέρειες. Θα μπορούσε απλώς αυτό να αναφερθεί σαν, ας πούμε, εγκυκλοπαιδική γνώση, αλλά όχι να αποτελέσει θέμα προς διδασκαλία και κατανόηση από τους μαθητές...

ApoAntonis

Παράθεση από: alkisg στις 07 Απρ 2020, 09:36:19 ΠΜ
Πάμε στην Python ή σε οποιαδήποτε άλλη γλώσσα και γράφουμε:
print(0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 1)

Απαντάει "False". Δηλαδή αν προσθέσουμε δέκα φορές το 0.1, δεν μας κάνει 1, αλλά 0.999999999.

δίκοπο...
print 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 0.999999999
ούτε και αυτό δίνει True
(με 16 εννιάρια όμως αλλάζει το αποτέλεσμα)

ενώ το
print 1.0/3 + 1.0/3 +1.0/3 == 1
παράγει True





alkisg

Ναι το 0.999999999 το είπα για συντομία, όχι ως ακριβές αποτέλεσμα. Για μεγαλύτερη ακρίβεια, στη C:
    printf("%0.60lf\n", 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1);
Τυπώνει: 0.999999999999999888977697537484345957636833190917968750000000

Επομένως ο Διερμηνευτής μένει ως έχει, ενώ αν ποτέ το γυρίσουμε σε Python, τότε θα πρέπει ο κάθε καθηγητής να αποφεύγει παραδείγματα που εμπλέκουν οριακές συγκρίσεις πραγματικών αριθμών, όπως είναι οι επαναλήψεις με πραγματικό βήμα, π.χ. ΓΙΑ μ ΑΠΟ 0 ΜΕΧΡΙ 1 ΜΕ_ΒΗΜΑ 0.1.

alkisg

Υ.Γ. βρήκα μικρότερο παράδειγμα στο https://docs.python.org/3/tutorial/floatingpoint.html
print(0.1 + 0.1 + 0.1 == 0.3)
Βγάζει False.

Ή αντίστοιχα μια ΓΙΑ σε C:
Κώδικας: C
int main(void) {
    double f;
    for (f = 0.1; f <= 0.3; f += 0.1)
        printf("%0.60lf\n", f);
}


Κάνει μόνο 2 επαναλήψεις:
0.100000000000000005551115123125782702118158340454101562500000
0.200000000000000011102230246251565404236316680908203125000000
Ενώ δεν δείχνει την επόμενη, αφού είναι πάνω από 0.3:
0.300000000000000044408920985006261616945266723632812500000000
Ακριβώς 0.3 δεν υπάρχει, οπότε η σταθερά 0.3 ουσιαστικά είναι η:
0.299999999999999988897769753748434595763683319091796875000000).

Και φυσικά αντίστοιχο πρόβλημα δημιουργείται και στις συναρτήσεις τύπου Ακέραιο Μέρος...

George Eco

#5
Άργησα να το δω αυτό...
Συμφωνώ πως είναι δίκοπο μαχαίρι.
Από τη μία αφαιρείται ΟΛΟ το κομφούζιο του (0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 <> 1) = ΑΛΗΘΗΣ
από την άλλη αν το εφαρμόζεις σε πηλίκα, έχει κακό αποτέλεσμα.

Αν το πάμε κατά κανόνα, επί χάρτου στη ΓΛΩΣΣΑ έχουμε άπειρη ακρίβεια.
Μου κάθεται στο λαιμό αυτό βέβαια.

Παράθεση από: ApoAntonis στις 07 Απρ 2020, 11:52:46 ΠΜ
δίκοπο...
print 0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 == 0.999999999
ούτε και αυτό δίνει True
(με 16 εννιάρια όμως αλλάζει το αποτέλεσμα)

ενώ το
print 1.0/3 + 1.0/3 +1.0/3 == 1
παράγει True


Βασικά η εντολή
print 1.0/3 + 1.0/3 +1.0/3 == 1
παράγει True για το λόγο που αναφέρεις παραπάνω συνάδελφε.
Ξεπερνά τα 16 εννιάρια κατά την άθροιση.

Κι εδώ είναι που μου κάθεται και πάλι στο λαιμό η ΓΛΩΣΣΑ. Επί χάρτου έχουμε άπειρη ακρίβεια.
Με το δίκιο του ο Άλκης θέλει να μη κάνει τα παιδάκια να τραβάνε τα μαλλιά τους,
για να κατανοήσουν γιατί  0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1+0.1 = 0.999999999 κι όχι 1.0
βάσει της πεπερασμένης ακρίβειας vs της άπειρης ακρίβειας
από την άλλη, πρέπει μάλλον τα παιδιά της Γ Λυκείου να μαθαίνουν τι τρέχει λίγο under the hood.

Αυτό όμως θα αύξανε τη δυσκολία του μαθήματος εκθετικά σε αυτό το σημείο, δίχως κάποιο ουσιαστικό όφελος για τα παιδιά.
"Αφού επί χάρτου είναι άπειρη η ακρίβεια στη ΓΛΩΣΣΑ, τι νόημα έχει να μας το εξηγείτε αυτό για τις Πανελλήνιες κύριε;"
Τι απαντάμε εδώ;
Θα μου πείτε δε τους μιλάμε ποτέ για άπειρη ακρίβεια; Για πόση ακρίβεια μιλάμε τότε;
Κι ερχόμαστε στο προβληματισμό του Άλκη! ::)
Διότι δύο δεκαδικά είναι μια αποδεκτή ακρίβεια, κι η άπειρη ακρίβεια επί χάρτου μου κάθεται στο λαιμό.
Τελικά, στις Πανελλήνιες, υπάρχουν, οδηγίες, πλαίσιο, ρητή διευκρίνιση του πόση είναι η ακρίβεια;
Για Πανελλήνιες αυτό μας νοιάζει. Για το τι γίνεται under the hood, μπορώ να συμφωνήσω, πως μπορούν να το μάθουν ως πρωτοετείς Φοιτητές αυτό. Δε θα δυσκολευόμουν πολύ να τους το εξηγήσω, αλλά θα μου έπαιρνε μία με δύο ώρες ανάλογα το επίπεδο της τάξης. Δεν είναι απλό να το εξηγήσεις.


Παράθεση από: alkisg στις 07 Απρ 2020, 12:32:04 ΜΜ
Επομένως ο Διερμηνευτής μένει ως έχει, ενώ αν ποτέ το γυρίσουμε σε Python, τότε θα πρέπει ο κάθε καθηγητής να αποφεύγει παραδείγματα που εμπλέκουν οριακές συγκρίσεις πραγματικών αριθμών, όπως είναι οι επαναλήψεις με πραγματικό βήμα, π.χ. ΓΙΑ μ ΑΠΟ 0 ΜΕΧΡΙ 1 ΜΕ_ΒΗΜΑ 0.1.
:)
Καλή σκέψη θα έλεγα. Αν γυρίσει θε python θα πρέπει να συμπεριληφθεί αυτό στο βιβλίο Καθηγητή ως ρητή οδηγία θα έλεγα και να βγάλουν εκτός ύλης το δεκαδικό βηματισμό ως εκτός πλαισίου μαθήματος φέρει πειν, στυλ "υπάρχει, γίνεται, αλλά δε θα ασχοληθούμε στο μάθημα με αυτό".

Εναλλακτικά θα ΠΡΕΠΕΙ να μιλάμε για πεπερασμένη ακρίβεια αναγκαστικά. Δεν έχω κανένα πρόβλημα να γίνει έτσι στο μάθημα, φτάνει να είναι ρητά ορισμένο στην ύλη. Δύσκολο να το διδάξεις, όχι απίθανο όμως.

alkisg

Παράθεση από: George Eco στις 27 Ιουλ 2020, 09:29:13 ΜΜ
από την άλλη αν το εφαρμόζεις σε πηλίκα, έχει κακό αποτέλεσμα.

Εφαρμόζεται σε συγκρίσεις, όχι σε πράξεις. Οι πράξεις γίνονται κανονικά χωρίς καμία στρογγυλοποίηση.
Π.χ. αν το 1/3 σαν πράξη έχει διαφορετικό αποτέλεσμα από το 3/9 (δεν το κοίταξα), τότε με αυτή την επιλογή το 1/3 = 3/9 θα είναι ΑΛΗΘΗΣ.

Πρόσφατα είδα ότι και ο Knuth είχε κάνει κάτι αντίστοιχο στο πασίγνωστο βιβλίο The Art of Computer Programming από όπου έχουν αντιγραφεί πολλά σημεία της ΑΕΠΠ.
Εκεί, είχε προδιαγράψει τον ιδεατό υπολογιστή MIX για τη διδασκαλία assembly MIXAL. Ο επεξεργαστής του MIX έχει μόνο μία εντολή για συγκρίσεις πραγματικών αριθμών, την FCMP (float compare). Ο Knuth όρισε ότι στη θέση 0 της RAM υπάρχει μια ειδική καθολική μεταβλητή ονόματι EPSILON, την οποία χρησιμοποιεί η FCMP στις συγκρίσεις. Έτσι, αν κάποιος βάλει 0 στο EPSILON, είναι σαν να απενεργοποιεί την επιλογή αυτή, ενώ αν βάλει π.χ. 0.0001, τότε οι συγκρίσεις γίνονται με προσέγγιση 4 δεκαδικών ψηφίων.

Παράθεση από: https://esolangs.org/wiki/MIX_(Knuth)
FCMP does tolerant comparison of rA with the memory word at address M, the tolerance is given by the word at address 0, output to the comparison flags.

George Eco

Ναι εννοούσα τη σύγκριση αθροίσματος κλασμάτων τύπου 1/3 + 1/3 + 1/3 = 1

Πολύ ενδιαφέρον αυτό με τον Knuth Άλκη. Δε το έχω διαβάσει το βιβλίο και μου βάζεις ζιζάνια τώρα!  :D ;D
Κι ευχαριστώ γι' αυτό! Τον ξέρω τον Knuth από τα Numberphille - Computerphille Youtube Clannels και δε μπήκα ποτέ σε διαδικασία να δω τι έχει γράψει.