Τετάρτη 23 Σεπτεμβρίου 2020

Τομή δύο γραμμών (χρήση OOP)

Το πρόγραμμα περιέχει ένα τμήμα το οποίο δέχεται δυο αυτόματους πίνακες (tuple) που ο καθένας περιέχει τέσσερις αριθμούς, ή δυο σημεία στο επίπεδο όπου ορίζουν μια γραμμή. Δηλαδή δίνουμε στο τμήμα Τομή2Γραμμών δυο γραμμές με δυο σημεία για κάθε γραμμή (τα σημεία πρέπει να είναι διαφορετικά σε μια γραμμή, δηλαδή δεν ορίζουμε γραμμή με ένα σημείο που το δίνουμε δυο φορές, ή δυο σημεία όπου έχουν το ίδιο Χ αλλά διαφορετικό Ψ).

Η απάντηση του τμήματος θα είναι ή απροσδιόριστο ή το σημείο τομής των γραμμών, ή θα βγάλει λάθος και θα σταματήσει το πρόγραμμα αν δώσουμε δυο σημεία με ίδια τιμή Χ (σαν να δίναμε ένα σημείο δυο φορές).

Εντός του τμήματος Τομή2Γραμμών θα ορίσουμε μια κλάση, την κλάση Γραμμή. Όταν θα φτιάξουμε δυο αντικείμενα τύπου γραμμή, τότε θα έχουμε φτιάξει (και υπολογίσει) σε αυτά τα αντικείμενα ως ιδιωτικά μέλη την κλήση και μια σταθερά. Αυτά τα δυο χρειάζονται αν θέλουμε να χρησιμοποιήσουμε το δημόσιο μέλος, τη μέθοδο Φ(χ), αλλά και την άλλη μέθοδο Τομή(άλλη_γραμμή).

Η μέθοδος Φ(χ) δίνει το ψ για κάθε χ. Η μέθοδος Τομή(άλλη_γραμμή) δέχεται ένα αντικείμενο γραμμή, και δίνει έναν αυτόματο πίνακα. Αυτός ο πίνακας μπορεί να μην έχει στοιχεία, και αυτό σημαίνει "απροσδιόριστο" ή να έχει δυο στοιχεία, το σημείο τομής.

Απροσδιόριστο έχουμε αν οι γραμμές είναι παράλληλες, είτε συμπίπτουν είτε όχι. Αν συμπίπτουν τότε δεν υπάρχει ένα σημείο τομής, όλα τα σημεία της μιας γραμμής είναι σημεία και της άλλης. Αν δεν συμπίπτουν τότε δεν υπάρχει σημείο τομής (στα μαθηματικά δυο παράλληλες πιθανόν να τέμνονται σε άπειρη απόσταση). Ουσιαστικά ο έλεγχος γίνεται στις κλίσεις των γραμμών με τελεστή == ο οποίος ελέγχει την ισότητα με περιορισμένη ακρίβεια (13 δεκαδικών) και όχι 15-16 που έχουν οι διπλής ακριβείας. Αυτό σημαίνει ότι ενδέχεται να έχουμε διαφορετικές κλήσεις αλλά να είναι πολύ κοντά, σχεδόν παράλληλες οι γραμμές, οπότε τις δεχόμαστε ως παράλληλες. Τυπικά το σημείο τομής σε αυτή τη περίπτωση "σχεδόν παράλληλες γραμμές" είναι κοντά στο άπειρο, δεν έχει δηλαδή νόημα να γνωρίζουμε τον αριθμό! Έτσι τιμή απροσδιόριστο επιστρέφει όταν έχουμε παράλληλες ή σχεδόν παράλληλες γραμμές.

Τα μέλη κλήση και σταθερά είναι ιδιωτικά. Από τη στιγμή που φτιάχνουμε ένα αντικείμενο τύπου γραμμή, έχουμε τα νούμερα για αυτά τα δυο ιδιωτικά μέλη. Όταν δώσουμε ένα αντικείμενο τύπου γραμμή στη συνάρτηση Τομή() τότε επειδή η συνάρτηση είναι σε ίδιου τύπου αντικείμενο κάνει τα ιδιωτικά μέλη του αντικειμένου εισαγωγής να φαίνονται ως δημόσια (για τη συνάρτηση μόνο).

Το Πρόγραμμα

Τμήμα Τομή2Γραμμών (Α_2Σημεία, Β_2Σημεία) {

      Κλάση Γραμμή {
      ιδιωτικό:
            κλίση, σταθερά
      δημόσιο:
            Συνάρτηση Φ(χ) {
                  =χ*.κλίση-.σταθερά
            }
            Συνάρτηση Τομή(άλλη_γραμμή ως Γραμμή) {
                  αν άλλη_γραμμή.κλίση==.κλίση τότε
                        =(,)
                  αλλιώς
                        χ1=(.σταθερά-άλλη_γραμμή.σταθερά)/(.κλίση-άλλη_γραμμή.κλίση)
                        =(χ1, .Φ(χ1))
                  τέλος αν
            }
      Κλάση:
            Τμήμα Γραμμή (χ1, ψ1, χ2, ψ2) {
                  αν χ1==χ2 τότε λάθος "λάθος στην εισαγωγή"
                  αν χ1>χ2 τότε άλλαξε χ1,χ2 : άλλαξε ψ1, ψ2
                  .κλίση<=(ψ1-ψ2)/(χ1-χ2)
                  .σταθερά<=χ1*.κλίση-ψ1
            }
      }
      ΓραμμήΑ=Γραμμή(!Α_2Σημεία)
      ΓραμμήΒ=Γραμμή(!Β_2Σημεία)
      Αποτέλεσμα=ΓραμμήΑ.Τομή(ΓραμμήΒ)
      τύπωσε "Τομή:",
      αν μήκος(Αποτέλεσμα)=0 τότε
            τύπωσε "Απροσδιόριστο"
      αλλιώς
            τύπωσε Αποτέλεσμα
      τέλος αν
}
Τομή2Γραμμών (4,0,6,10), (0,3,10,7) '    5  5
Τομή2Γραμμών (0,0,1,1), (1,4,2,5) ' Απροσδιόριστο
Τομή2Γραμμών (0,0,1,1), (0,0,1,1) ' Απροσδιόριστο


Περί του Διερμηνευτή:

Παρακάτω αναπτύσσω μερικές ιδέες πάνω στη λειτουργία του διερμηνευτή της Μ2000. Ο διερμηνευτής φτιάχτηκε για να ανταποκριθεί στη σωστή λειτουργία των εντολών της Μ2000, και όχι για να εκτελείται με τη μέγιστη ταχύτητα. Έχουν γίνει βελτιστοποιήσεις όπως η εκτεταμένη χρήση πινάκων κατακερματισμού όπου άμεσα κάνουν αναζητήσεις ονομάτων (αναγνωριστικών), ανεξάρτητα από τον αριθμό των ονομάτων (εξαρτάται μόνο από το μήκος του ονόματος, τυπικά όμως ο χρόνος είναι αμελητέος, επειδή ούτως ή άλλως η λειτουργία των σύγχρονων υπολογιστών είναι ασύγχρονη με συνέπεια να εμφανίζονται καθυστερήσεις λόγω διαμοιρασμού φορτίου εκτέλεσης σε εφαρμογές που εκτελούνται ταυτόχρονα. 

Δείτε ότι στις συναρτήσεις στη Μ2000 δεν ορίζουμε το τύπο του αποτελέσματος, εκτός του βασικού, δηλαδή αν η συνάρτηση γυρίζει αλφαριθμητικό τότε πρέπει να έχει το $ στο όνομά της. Εδώ η Τομή() δεν γυρίζει αλφαριθμητικό. Μπορεί να γυρίσει αριθμό ή αντικείμενο (ως τιμή) ή δείκτη σε αντικείμενο. Εδώ γυρίζει έναν αυτόματο πίνακα. Η τιμή (,) είναι ο κενός πίνακας (μήκος 0), ενώ η τιμή (χ1, Φ(χ1)) είναι αυτόματος πίνακας δυο στοιχείων (μήκος 2).

Ονομάζουμε τα tuple ως αυτόματους πίνακες γιατί είναι πίνακες που ορίζονται άμεσα σε έκφραση, και όχι με ειδική εντολή όπως Πίνακας, Τοπικό, Τοπική, Τοπικές ή Γενικό, Γενική, Γενικές.

Ένας αυτόματος πίνακας έχει δείκτη, δηλαδή η Τομή() επιστρέφει δείκτη σε πίνακα. Η μεταβλητή Αποτέλεσμα ορίζεται με τη τιμή που παίρνει ως δείκτης σε πίνακα. Η τύπωσε Αποτέλεσμα εμφανίζει όλα τα στοιχεία του πίνακα σε στήλες, όπου είναι αριθμός ή αλφαριθμητικό, αλλιώς όπου είναι αντικείμενο αφήνει κενή στήλη.

Οι αυτόματοι πίνακες στη Μ2000 μπορούν να αλλάξουν τιμή. Πχ το Αποτέλεσμα+=100 αυξάνει κατά 100 όλα τα αριθμητικά μέλη του πίνακα. Το Αποτέλεσμα#Τιμή(0) δίνει την αριθμητική τιμή του πρώτου στοιχείου (όλοι οι αυτόματοι πίνακες ξεκινούν από το 0). Υπάρχουν αρκετές συναρτήσεις με # στην αρχή του ονόματος οι οποίες είτε δίνουν τελικό αποτέλεσμα είτε δίνουν αποτέλεσμα πίνακα και πάνω σε αυτό δίνουμε άλλη συνάρτηση, πχ στο παρακάτω από τα 1,2,3,4 βγάζουμε ένα πίνακα με στοιχεία από το 3ο (δείκτης 2) έως το 4ο (δείκτης 3), και από αυτόν τον πίνακα υπολογίζουμε το άθροισμα. Υπάρχουν συναρτήσεις με το # στην αρχή του ονόματος οι οποίες δέχονται λάμδα συναρτήσεις για να παράγουν έναν πίνακα ή ένα τελικό αποτέλεσμα.

Τύπωσε (1,2,3,4)#Μέρος(2,3)#Αθρ()=7

Δείτε παρακάτω ότι έχουμε φτιάξει εκφράσεις που φτιάχνουν πίνακες οι οποίοι εξαφανίζονται μετά (δεν κρατάμε κάποιον δείκτη). 

Τύπωσε "(3:4)"="("+(1,2,3,4)#Μέρος(2,3)#Γραφή$(":")+")"

Τύπωσε "("+(1,2,3,4)#Μέρος(2,3)#Γραφή$(":")+")"="(3:4)"

Επίσης δείτε ότι ο διερμηνευτής βρίσκει ότι το (1,2,3,4)#Μέρος(2,3)#Γραφή$(":") είναι αλφαριθμητικό χωρίς να το εκτελέσει λόγω του $ (και των κανόνων που ακολουθεί), οπότε το "("+...+")" το βλέπει σαν αλφαριθμητική έκφραση. Η Τύπωσε βρίσκει ότι έχει λογική έκφραση για δυο εκφράσεις αλφαριθμητικές. Ο διερμηνευτής πριν εκτελέσει την λογική έκφραση έχει "δει" μπροστά ότι έχει λογική έκφραση, χωρίς να ενδιαφέρεται για το τι υπάρχει μέσα σε παρενθέσεις, αλλά τι τελεστές υπάρχουν εκτός και αν υπάρχουν σε ονόματα (εκτός παρενθέσεων) το $. Επίσης από τα "" ή {} βλέπει επίσης αν έχει αλφαριθμητικά. Οι αγκύλες χρησιμοποιούνται για αλφαριθμητικά πολλαπλών γραμμών και για μπλοκ κώδικα. Ο χρωματιστής εντολών βρίσκει τι περίπτωση έχουμε γιατί ξέρει ποιες εντολές δέχονται μπλοκ κώδικα. Επίσης ένα γυμνό μπλοκ (χωρίς εντολή στην αρχή), το θέτει ο χρωματιστής άμεσα ως μπλοκ κώδικα επειδή δεν ξεκινάνε ποτέ σταθερές αλφαριθμητικών σε γραμμές εντολών (πάντα βρίσκονται σε εκφράσεις).

Αν κοιτάξει κανείς το κώδικα της Μ2000 στο github θα δει αρκετές lookahead() συναρτήσεις οι οποίες κοιτούν μπροστά είτε για να βγάλουν συμπέρασμα το τι έκφραση ακολουθεί (ο βασικός τύπος ένας από τους δυο: αριθμητικός (περιέχει και το λογικό) ή αλφαριθμητικός), είτε για να βρουν κάποιο τερματικό σε μια δομή, πχ στην Ενώ Τέλος Ενώ. Η δομή Ενώ υπάρχει και ως Ενώ { } όπου αντί για τερματικό Τέλος Ενώ έχει ένα μπλοκ, οπότε ο διερμηνευτής αρκεί να βρει που κλείνει το μπλοκ (μετρώντας σωστά τα φωλιασμένα μπλοκ), και αυτός είναι γενικά ο πιο γρήγορος τρόπος.

Κάποια στιγμή ο Διερμηνευτής θα αποκτήσει AST και τότε δεν θα έχει σημασία πως εμφανίζεται στο κείμενο η κάθε δομή (όπως αυτή της επανάληψης με την Ενώ), ως προς το χρόνο εκτέλεσης. Προς το παρόν ο διερμηνευτής εκτελεί πηγαίο κώδικα, που τεμαχίζει, κάθε φορά, και σχηματίζει δομές δεδομένων και τις καταργεί όποτε χρειάζεται. Ο διερμηνευτής είναι "καταναλωτής" κώδικα. Όταν καταναλωθεί ο κώδικας τότε τερματίζει. Μια εντολή Έξοδος διαγράφει τον υπόλοιπο κώδικα. Ένα μπλοκ κώδικα "τεμαχίζει" τον κώδικα, και εκτελείται σαν να είναι μόνος του.



Δεν υπάρχουν σχόλια:

Δημοσίευση σχολίου

You can feel free to write any suggestion, or idea on the subject.