Κυριακή 30 Απριλίου 2017

Αναθεώρηση 16 (Έκδοση 8.7) - Προσθήκη Επεξηγήσεων!

Βελτιώθηκε η ταχύτητα στο χειρισμό των αντικειμένων.
Εδώ έχουμε μια κλάση, που παράγει αντικείμενα. Το τμήμα Class: δεν θα περάσει στις παρουσίες των αντικειμένων.
Χρησιμοποιούμε ένα αντικείμενο Σωρός (ειδική στοίβα) και εκεί βάζουμε μερικά αντικείμενα. Έχουμε δυο ρουτίνες ταξινόμησης, μια Selection Sort  ή ταξινόμηση με επιλογή (εδώ την λέμε StackSort) και η άλλη είναι η quicksort.
Στην πρώτη ρουτίνα ταξινόμησης χρησιμοποιείται σωρός με επισροφές τιμών απευθείας σε στοιχεία. Ο σωρός είναι συνδεδεμένη λίστα, και κανονικά με την Βάλε ή Push βάζουμε στη κορυφή και με την Σειρά ή Data βάζουμε στο πυθμένα. Η Διάβασε ή Read διαβάζει πάντα από την κορυφή (και πετάει την τιμή)
Με την χρήση του StackItem() ή ΤιμήΣωρού()  (και StackItem$() ή ΤιμήΣωρού$() για αλφαριθμητικά), διαβάζουμε χωρίς να πετάμε τιμές. Αν θέλουμε μπορούμε με την Επιστροφή να επιστρέψουμε τιμές σε θέσεις (να τις αλλάξουμε δηλαδή). Η εντολή επιστροφή αλλάζει πολλές τιμές αν θέλουμε (παίρνει λίστα). Δείτε όμως ότι για να λειτουργήσει θέλει δείκτη σε σωρό. Μπορούμε να πάρουμε τον τρέχον σωρό σε ένα δείκτη με αυτό Αλφα=[]  (το [] είναι ο τρέχον σωρός), και ο τρέχον σωρός θα αδειάσει. Μπορούμε να επιστρέψουμε τις τιμές από το Αλφα με την Σωρός Άλφα (θα μπούνε οι τιμές στο τέλος του σωρού, οπότε αν είναι άδειος ο τρέχουν θα έχει τις τιμές του Άλφα, και ο Άλφα θα αδειάσει).






Class M {
       x=10, y=30
      Function comp (mm) {
            = Compare(.x,mm.x)
      }
      operator ">"  (mm) {
            Push .x>mm.x
      }
      value {
            =.x*.y
      }
Class:
      Module M (.x,.y) {}
}
N=Stack:=M(10,30), M(4,15), M(50,60),M(3,15), M(33,16), M(34,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(13,15), M(33,16), M(124,15) , M(10,30), M(4,15), M(50,60),M(13,15), M(33,16), M(4,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(23,15), M(33,16), M(24,15)
Inventory Const="Ascending":=1, "Descending":=-1
Profiler
If Len(N)>1 then SortStack(each(N, 1, Len(N)-1),Const("Ascending"))
Print timecount
Print "Press Any Key, for list - sorted by second column from left"

A$=Key$
Print "xxxxxxxxxxxxxxxxxxxxxxxxxxXXXXxxxXXXXxxxxxxxx"
ShowN(Each(N))

N=Stack:=M(10,30), M(4,15), M(50,60),M(3,15), M(33,16), M(34,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(13,15), M(33,16), M(124,15) , M(10,30), M(4,15), M(50,60),M(13,15), M(33,16), M(4,15), M(33,16), M(4,15), M(10,30), M(54,15), M(50,60),M(23,15), M(33,16), M(24,15)
Profiler
Stack N {
      quicksort(1, Len(N), Const("Ascending"))
}
Print timecount
Print "Press Any Key, for list - sorted by second column from left"

A$=Key$
Print "xxxxxxxxxxxxxxxxxxxxxxxxxxXXXXxxxXXXXxxxxxxxx"
ShowN(Each(N))
Sub SortStack(Nrep1, cc)
While Nrep1 {
      Nrep2=Each(Nrep1, Nrep1^+1)
            Let temp1=stackitem(Nrep1)
            ok=FALSE
            While Nrep2 {
                              let temp2=stackitem(Nrep2)
                              If compare(temp1.x,temp2.x)=cc then {
                              return Nrep2, Nrep2^+1:=Group(temp1)
                              let temp1=group(temp2)
                              ok=TRUE
            }
           If ok then return Nrep1, Nrep1^+1:=Group(temp1)
      }
}
End Sub
Sub ShowN(Nrep)
      While Nrep {
                 Let temp=stackitem(Nrep)
                  Print temp, temp.x, temp.y, Nrep^+1
      }
End Sub
Sub quicksort(first, last, cc)
      Local thing(1), i=first, Limit=last+1
      If Limit >2 Then Shift (Limit+i) Div 2
      Read thing(0)
      Limit--
      For thing(0) {
            While i<Limit {
                  If .comp(stackitem(i))=-cc then {
                        Limit--
                        If i>1 Then Shift i
                        ShiftBack Limit
                  }  Else i++
            }
            If i>Limit Then i=Limit
            Push group(This)
            }
     dim thing()
      ShiftBack i
      If i>first Then quicksort(first,i-1, cc)
      If last>i Then quicksort(i,last, cc)
End Sub


Μια εξήγηση για το thing(1) και λίγα λόγια για τα αντικείμενα.  Εκτός από την Πϊνακας (Dim) για να ορίσουμε πίνακες μπορούμε να ορίζουμε και με την Local (Τοπική ή Τοπικές) ή και την Global (Γενική ή Γενικές). Δεν έχουμε όμως τα ίδια επιπλέον που μας δίνει η Πίνακας (πχ την αλλαγή βάσης), αλλά μπορούμε εκ των υστέρων να την χρησιμοποιήσουμε (όταν θα υπάρχει ήδη το αντικείμενο - εσωτερικά οι πίνακες είναι αντικείμενα στη Μ2000).
Εδώ στην quicksort θέλουμε να διαβάσουμε το αντικείμενο σε θέση πίνακα. Όταν γίνεται αυτό το αντικείμενο είναι κλειστό, δηλαδή περιέχει οτιδήποτε μόνο για το ίδιο. Αν το διαβάσουμε με όνομα, τότε δημιουργείται το λεγόμενο ανοικτό και όλα τα μέλη γίνονται ταυτόχρονα μέλη του τμήματος που διαβάστηκε (οι ρουτίνες είναι μέρος του τμήματος, στο οποίο ότι δημιουργούμε διαγράφεται). Επειδή θέλουμε να καλέσουμε με αναδρομή την quicksort μας βολεύει το αντικείμενο να μην παίρνει χώρο στις λίστες μεταβλητών/συναρτήσεων, ως ανοικτό, και να ανοίγει μόνο όταν χρειάζεται. Το πρόσκαιρο άνοιγμα το κάνει η For thing(0) { } και έτσι εντός του μπλοκ το .comp() σχετίζεται με αυτό το αντικείμενο.
Η δυσκολία (που δεν φαίνεται με μια ματιά) βρίσκεται στο ότι έχουμε το αντικείμενο έτσι φτιαγμένο ώστε να γυρνάει τιμή (το Χ*Υ). Η Stackitem() όμως δεν γυρνάει τιμή αλλά ένα αντίγραφο του αντικειμένου (δεν δίνει δείκτη στο αντικείμενο ομάδα, ενώ σε άλλα αντικείμενα που τα χρησιμοποιούμε με δείκτη προς αυτά όντως δίνει δείκτη).
Επειδή βγάζουμε από την λίστα (σωρός τιμών) ένα αντικείμενο και το βάζουμε στην Thing(0) (ένα στοιχείο, με βάση το 0, άρα θα είναι στην θέση 0), θα πρέπει να το βάλουμε πάλι στη θέση του. Αν κάναμε αυτό Βάλε Thing(0) θα έδινε την τιμή X*Y και όχι το αντικείμενο. Η Ομάδα() ή Group() θέλει ένα ανοικτό αντικείμενο και αφού το βρει δίνει το αντίγραφό του σε κλειστό (μαζεύει ότι έχει μέσα στο χώρο του αντικειμένου, ενώ στο ανοικτό, ο χώρος του αντικειμένου είναι μια λίστα με ονόματα και θέσεις στο χώρο μεταβλητών/συναρτήσεων, χωρίς τιμές). Δίνουμε το This (Αυτό) που ο διερμηνευτής γνωρίζει ότι είναι το ανοικτό αντικείμενο που έβγαλε η For Thing(0) { }. Θα μπορούσαμε να τo περάσουμε και με  αναφορά πχ Τμήμα1 &Αυτό σε ένα τμήμα Τμήμα1 (αρκεί εκεί να υπάρχει η Διάβασε &έναόνομα). Έτσι βάζουμε στο σωρό το Group(This) με την Push Group(This), ως αντίγραφο του This. Μόλις τερματίσει το μπλοκ For Thing(0) { } αυτόματα ξανακλείνει το αντικείμενο, πετάει το παλιό στο Thing(0) και βάζει το νέο (στο πίνακα έχουμε Variant γιατί αυτός ο τύπος μπορεί να πάρει δείκτες προς αντικείμενα, αλλά και τιμές όπως double ή τύπου string).
Αν έχουμε βάθος κλήσεων έστω 10 στην quicksort (την ρουτίνα όπως έχουμε εδώ) τότε το τμήμα θα έχει δέκα πίνακες Thing(0) και ο ενεργός θα είναι ο τελευταίος. Κάθε φορά που κάνουμε επιστροφή από την ρουτίνα, καθαρίζονται οι λίστες μεταβλητών/συναρτήσεων, στο σημείο που ήταν πριν την κλήση.
Η Μ2000 δεν τοποθετεί τις μεταβλητές και τις συναρτήσεις στην στοίβα εκτέλεσης. Οι λίστες μεταβλητών και συναρτήσεων είναι δυναμικοί πίνακες με λειτουργία συνάρτησης κατακερματισμού (για να βρίσκει γρήγορα τα ονόματα), με την ιδιομορφία να αυξομειώνονται (όχι υποχρεωτικά και ο χώρος τους κάθε φορά), πάντα από το τέλος, το πιο πρόσφατο, και να περιέχουν ίδια κλειδιά (ίδια αναγνωριστικά). Με αυτόν τον τρόπο πετυχαίνεται η σκίαση μεταβλητών. Το πραγματικό όνομα μιας μεταβλητής έχει να κάνει με το όνομα που βλέπουμε και το πρόθεμα που παίρνουν από το τμήμα που βρίσκονται. Δεν μας απασχολεί αυτό, αφού δουλεύει, αλλά έχει σημασία να γνωρίζουμε ότι αντικείμενα που είναι σε πίνακες έχουν κρυφό όνομα που αποδίδεται από το σύστημα όταν ανοίγουν. Το άνοιγμα σημαίνει να περαστούν τα ονόματα μεταβητών/συναρτήσρων στις λίστες ώστε να μπορούν να χρησιμοποιηθούν. Εδώ δεν έχουμε κάποια διεπαφή (interface) να παίρνει το όνομα της συνάρτησης της ομάδας και να το αναζητεί σε αυτό, αλλά απευθείας καλείται η συνάρτηση ως υπάρχουσα σαν όλες τις άλλες. Στην κλήση όμως η συνάρτηση ενημερώνει ότι ανήκει σε αντικείμενο με συγκεκριμένο πρόθεμα, οπότε οι μεταβλητές .Χ και .Υ θα πάρουν το σωστό πρόθεμα (και θα βρεθούν άμεσα στη λίστα μεταβλητών). Έτσι οι ομάδες (Groups) στην M2000 δεν έχουν Διεπαφή/interface, ξεχωριστό από το χρήστη, παρά μόνο ένα βασικό (υποχρεωτικά) που διαχειρίζεται εσωτερικά ο διερμηνευτής. Οι κλάσεις είναι συναρτήσεις που παράγουν ομάδες. Έτσι υπάρχει η νοητή διεπαφή, τα μέλη της ομάδας. Θα βγει λάθος κατά την εκτέλεση αν ζητάμε ένα μέλος που δεν υπάρχει. Οι ομάδες μπορούν να αυξάνουν τα μέλη τους, ενώ δεν υπάρχει διαγραφή μελών. Αυτό που υπάρχει είναι η συγχώνευση,  δηλαδή έχουμε μια ομάδα Α και θέλουμε να έχει επιπλέον τα μέλη της Β, μπορούμε με το Α=Β να δώσουμε αντίγραφο μελών του Β στο Α (αν το Β και το Α δεν έχουν Αξίες, δεν λειτουργούν ως μεταβλητές με τιμές αριθμητικές ή αλφαριθμητικές). Ή μπορούμε να έχουμε μια νέα ομάδα Ζ και σε αυτήν να βάλουμε το Ομαδα(Α) και Ομάδα(Β), διαδοχικά: Ζ=Ομάδα(Α) και Ζ=Ομάδα(Β), και έτσι θα έχουμε την Ομάδα Ζ με τα μέλη του Α και του Β (αν το Β έχει κάποια ίδια μέλη με το Α τότε το Ζ θα εχει μια φορά αυτά τα μέλη με τις τελευταίες τιμές, αυτές του Β). Επειδή η Μ2000 έχει την δυνατότητα δημιουργίας πρόσκαιρων ορισμών, τόσο ως τοπικές σε  τμήμα/συνάρτηση/ρουτίνα όσο και στα μπλοκ με Για αντικείμενο { } (και σαν γενική μορφή υπάρχει το Για Αυτό { }) να έχουμε ομάδες όπως η Ζ να εξυπηρετούν το σκοπό μας και μετά βάζουμε στο Α ας πούμε ένα τμήμα που θα διαβάζει με αναφορά το Ζ και θα παίρνει τις νέες τιμές που θέλουμε να κρατήσουμε μετά τη διαγραφή του (το Ζ ας πούμε είναι προσωρινό).
Με την συγχώνευση μελών η Μ2000 πετυχαίνει να δημιουργεί ομάδες από άλλες ομάδες, άρα κατά μια έννοια να προσθέτει λειτουργικότητα. Στη Μ2000 όπως μπορούμε να έχουμε τμήματα/συναρτήσεις/ρουτίνες σε τμήματα/συναρτήσεις, και τμήματα/συναρτήσεις σε ρουτίνες (μπορούμε να έχουμε ρουτίνες σε ρουτίνες, αλλά στην ουσία δεν έχει νόημα αφού οι ρουτίνες έχουν θέαση σε όλο το τμήμα απ όπου καλούνται, άρα κάπου θα βρούμε χώρο να βάλουμε κάποιες άλλες και όχι ειδικά μέσα σε μια ρουτίνα), έτσι και στις ομάδες μπορούμε να έχουμε ένα δένδρο ομάδων (μπορούμε να κάνουμε συγχωνεύσεις σε ομάδες που βρίσκονται σε άλλες ομάδες, αρκεί να μην γυρνούν ή δέχονται τιμή ως μεταβλητές). Μια ομάδα μπορεί να έχει οτιδήποτε εκτός από ρουτίνες (ρουτίνες μόνο τα τμήματα και οι συναρτήσεις έχουν, και αυτά όμως που βρίσκονται σε ομάδες). Μπορούμε ακόμα να έχουμε κλάσεις σε ομάδες, για να δημιουργούν δικές τους ομάδες (οι ομάδες επιστρέφονται ως κλειστά αντικείμενα και από συναρτήσεις, αλλά τοποθετούνται σε πίνακες, καταστάσεις  (λίστες με κλειδί) και σωρούς (ειδικές στοίβες τύπου συνδεδεμένης λίστας σε μια απλή διάταξη γραμμής, όπου η μετακίνηση θέσης είναι ανέξοδη, σε χρόνο και πόρους)
Αξίζει να αναφερθεί ότι μπορούμε σε κάθε θέση σε πίνακα, κατάσταση, σωρό να έχουμε οτιδήποτε. Ένας πίνακας δηλαδή μπορεί να έχει στις θέσεις του άλλους πίνακες και αυτοί να έχουν σωρούς, και οι σωροί να έχουν ομάδες. 'Η να έχουμε πίνακες με καταστάσεις (δουλεύουν με πίνακα κατακερματισμού, άρα με γρήγορη αναζήτηση) και σε κάθε στοιχείο κατάσταση να έχουμε πίνακα ή σωρό ή άλλη κατάσταση.
Τα αντικείμενα σωρός, κατάσταση, και ο λεγόμενος αυτόματος πίνακας (είδος πίνακα) δουλεύονται με δείκτη (αλλά στην τιμή του δεν έχουμε πρόσβαση), αλλά μεταβιβάζεται. Αυτό σημαίνει όμως ότι μπορεί μια κατάσταση Α να έχει σε στοιχείο της δείκτη στον εαυτό της ή σε άλλη Β όπου εκεί να υπάρχει δείκτης στην Α. Για το λόγο αυτό υπάρχει σύστημα που γνωρίζει πώς θα "Σκουπίσει" στη περίπτωση διαγραφής (σε προσωρινές-τοπικές), και αυτό λέγεται συλλέκτης σκουπιδιών. Η εντολή Λίστα αναφέρει αν υπάρχουν αντικείμενα με πολλαπλούς δείκτες προς αυτά. Ο καθαρισμός γίνεται αυτόματα, αλλά γίνεται και με το Clear ή Καθαρό που σβήνει μεταβλητές και κάνει και έλεγχο για καθαρισμό (αν χρειάζεται).






Σάββατο 29 Απριλίου 2017

Αναθεώρηση 15 (Έκδοση 8.7)

Σε αυτήν την αναθεώρηση διόρθωσα ένα λάθος στην ένωση πινάκων. Η ένωση δούλευε για μονοδιάστατους αλλά όχι σε περίπτωση που ο πρώτος στην ένωση ήταν με δυο ή περισσότερες διαστάσεις. Σε Wine (Linux) προκαλούσε άμεση διακοπή του διερμηνευτή, ενώ σε Windows απλά δεν έκανε την ένωση (προφανώς στο Wine δεν γίνεται καλό exception handling)

Στα αγγλικά η ένωση είναι το cons() (το έχω πάρει από την Lisp).
Στα ελληνικά είναι ένωση()


dim a(2,5)=10, b()
b()=a()
b=b()
b-=5
Print b()
Print
Print b
Print
Print Dimension(a()) ' 2
a()=cons(b(),a())
Print Dimension(a()) ' 1
dim a(2,10)
Print Dimension(a()) ' 2
Print a()

Απλά Μικρά Προγράμματα


Τα παρακάτω προγράμματα τα γράφουμε σε ένα τμήμα έστω Α και τα εκτελούμε με το όνομα του τμήματος.

Εισαγωγή Αριθμών με Δημιουργία Μεταβλητών

Εισαγωγή "Δώσε α , β: ", α, β
Τύπωσε "άθροισμα α+β="; α+β
Μπορούμε να δώσουμε και αριθμούς με δεκαδικά. Με την τελεία δίνουμε το σημείο δεκαδικών, μπορεί να είναι κόμμα ή τελεία. Με το κόμμα ή το Enter πάμε στην επόμενη εισαγωγή.

Εισαγωγή Ακεραίων Αριθμών με Δημιουργία Μεταβλητών

Εισαγωγή "Δώσε α , β: ", α%, β%
Τύπωσε "άθροισμα α+β="; α%+β%
Λίστα
Η εντολή Λίστα θα μας δείξει
τις μεταβλητές, με ! αμέσως μετά θα δείξει τις μεταβλητές με χρήση αναλογικής γραφής. (δοκιμάστε το Λίστα !)

Πράξεις με ακέραιες τιμές

Μ=1.3343
Τύπωσε Ακ(Μ) 'δίνει 1
Ζ=1.889
Τύπωσε Ακ(Ζ) ' δίνει 1
Τύπωσε Δεκ(Ζ) ' δίνει .889
Τύπωσε Στρογγ(Ζ,0) ' δίνει 2
Τύπωσε Στρογγ(Ζ,1) ' δίνει 1.9
Τύπωσε Στρογγ(Ζ,2) ' δίνει 1.89
Τύπωσε Στρογγ(-Ζ,2) ' δίνει -1.89
Τύπωσε Στρογγ(-Ζ,0) ' δίνει -2
Τύπωσε Ακ(-Ζ) 'δίνει -2, τον αμέσως κοντινότερο ακέραιο προς τα κάτω

Τύπωσε 5 δια 1.5 ' δίνει 5 γιατί πρώτα κάνει ακέραια την 1.5
Τύπωσε 6 δια -1.5 ' δίνει -3 γιατί κάνει το Ακ(-1.5) άρα το -2

Τύπωσε 7 υπόλ 2 ' δίνει  1
Τύπωσε 7 υπόλ -2 ' δίνει  1  
Τύπωσε -7 υπόλ 2 ' δίνει  -1

Τύπωσε 5 δια 1.5 ' δίνει 5 γιατί πρώτα κάνει ακέραια την 1.5 '  ΟΧΙ ΔΙΝΕΙ 3
Τύπωσε 6 δια -1.5 ' δίνει -3 γιατί κάνει το Ακ(-1.5) άρα το -2 ' ΔΙΝΕΙ -4
Στις νέες εκδόσεις το ΔΙΑ με μη ακέραιο τύπο δίνει πάντα ακέραια τιμή ως εξής, το 1.5 "χωράει" 3 φορές "ακέραιο" στο 5, άρα δίνει 3 και υπόλοιπο το 0.5

Υπάρχει το Δια# και Υπολ# που διαφέρει το αποτέλεσμα με αρνητικούς διαιρετέους. Στο ευκλείδειο υπόλοπο έχουμε πάντα  μηδέν ή θετικό αριθμό.
Πχ το -20 δια# 6 δίνει -4. το -20  υπολ#  6 δίνει 4, ισχύει πάντα ότι αν πολλαπλασιάσουμε το πηλίκο με το διαιρέτη και προσθέσουμε το υπόλοιπο θα πάρουμε τον διαιρετέο: Πράγματι -4*6 +4 μας δίνει το -20.
Στη κανονική διαίρεση, θα πάρουμε το -3 και το -2, έτσι το -3*6-2 θα μας δώσει το -20. 
Οι διαιρέσεις με το Δια και το Δια# δίνουν πάντα ακέραια τιμή (άσχετα από τύπο αριθμού). Αν έκαναν αυτό που γίνονταν στις παλιές εκδόσεις, πχ το 5 Δια 1.5 θα είχαμε το παράδοξο ή ανοθρόδοξο πέταγμα των δεκαδικών στο 1.5 άρα θα τροποποιούσαμε το διαιρέτη άρα θα είχαμε ένα αποτέλεσμα για 5 δαιρετέο και 1 διαιρέτη!  Οπότε το υπόλοιπο θα ήταν 0 και το πηλίκο το 5 και στον έλεγχο το 5*1.5+0 θα μας έδινε 7.5 διάφορο του 5, που σημαίνει ότι είναι λάθος αφού πρέπει να πάρουμε το 5. Σημασία έχει αυτό που δίνουμε και όχι η "τροποποίηση" του συστήματος.
Για το λόγο αυτό οι "ακέραια" διαίρεση δίνει "ακέραια" τιμή πάντα, αλλά το υπόλοιπο της οποιασδήποτε ακέραιας διαίρεσης ενδέχεται να έχει δεκαδικά, αν τουλάχιστον ένας από τους δυο αριθμούς, ο διαιρετέος ή ο διαιρέτης, έχει δεκαδικά. Σε αντίθεση με αυτό, αν και οι δυο αριθμοί είναι ενός τύπου ακέραιου πάντα (πχ είναι Long Long (64bit, Long 32bit, Integer 16bit) τότε λόγω του προηγούμενου κανόνα, επειδή δεν υπάρχουν δεκαδικά δεν θα προκύψουν δεκαδικά, στο υπόλοιπο. Σε κάθε περίπτωση τύπου, πάντα η διαίρεση μας λέει πόσες "Ακέραιες" φορές "υπάρχει" ο διαιρέτης στον διαιρετέο. Για το λόγο αυτό λέγεται "ακέραια διαίρεση" και όχι "διαίρεση ακεραίων". Αυτό ισχύει στα φυσικά προβλήματα, πχ αν κάποιος θέλει να φτιάξει "κουστούμια" που θέλουν 1.5 μέτρο ύφασμα, και έχουμε 5 πόσα κουστούμια θα φτιάξουμε; Αν "τροποποιήσουμε το 1.5 θα πάρουμε το 5, αλλά 5 κουστούμια δεν θα φτιάξουμε, βγαίνουν 3 και μένει μισό μέτρο "ρετάλι".



\\ Ευκλείδεια διαίρεση
α=-20
β=6
\\ Ευκλείδεια διαίρεση και υπόλοιπο
γ=α Διά# β
δ=α Υπόλ# β
Τύπωσε γ, δ ' -4   4
Τύπωσε α=β*γ+δ
\\ Κανονική διαίρεση και υπόλοιπο
γ=α Διά β
δ=α Υπόλ β
Τύπωσε γ, δ ' -3  -2
Τύπωσε α=β*γ+δ


Και οι ακέραιες μεταβλητές και οι πραγματικές (κινητής υποδιαστολής) εσωτερικά είναι ίδιου τύπου (double, πραγματικές). Οι τελεστές Δια και Υπόλ (υπάρχει και ως Υπόλοιπο) δουλεύουν με πραγματικές και αφαιρούν τα δεκαδικά. Η Υπόλ ή Υπόλοιπο αφαιρεί και το πρόσημο στο διαιρέτη. Οι εντολές μπορούν να γραφούν με πεζά ή κεφαλαία, με τόνους ή χωρίς (και λάθος τόνος δεν μας πειράζει, ο διερμηνευτής αφαιρεί τους τόνους στα ελληνικά κατά την εκτέλεση)


Στις συγκρίσεις το διπλό ίσον == κάνει πρώτα στρογγυλοποίηση στις τιμές που θα συγκρίνει στο 13ο δεκαδικό, ενώ το απλό δεν κάνει καμία στρογγυλοποίηση.

Επανάληψη εντολών με μετρητή και βήμα

Για ι=1 έως 1000 ανά 2 {
      Τύπωσε ι,
}
Τύπωσε

Για ι=1000 έως 1 ανά 2 {
      Τύπωσε ι,
}
Τύπωσε
Στη Μ2000 αν η αρχή είναι μεγαλύτερη από το τέλος της μέτρησης, τότε κατεβαίνει ο μετρητής. Το όριο τέλους μετράει για την εκτέλεση του μπλοκ εντολών. Το βήμα είναι θετικό.
Το ι θα πάρει μετά το πέρας της επανάληψης/μέτρησης την επόμενη τιμή εκτός ορίου


Για ι=1 εως 1 ανά -1 {
      Τύπωσε ι \\ δίνει 1
}
Τύπωσε ι \\ δίνει 0


Υπάρχει μια περίπτωση που το βήμα μας ενδιαφέρει αν είναι θετικό ή αρνητικό, όταν έχουμε αρχή και τέλος ίδιο όριο. Τότε ο διερμηνευτής αποφασίζει ποια θα είναι η τιμή μετά το πέρας της επανάληψης (μια φορά θα εκτελεστεί το μπλοκ εντολών), και αλλάζει ανάλογα την τιμή του μετρητή.
Για ι=1 εως 1 ανά -1 {
      Τύπωσε ι \\ δίνει 1
}
Τύπωσε ι \\ δίνει 0


Μπορούμε να χρησιμοποιούμε αριθμούς με δεκαδικά, και βήμα με δεκαδικά.
Για ι=1.5 έως 10 ανά .3 {
      Τύπωσε ι,
}
Τύπωσε


Θα μας δώσει αυτό: 1.5, 1.8, 2.1, 2.4, 2.7, 3, 3.3, 3.6, 3.9, 4.2, 4.5, 4.8, 5.1, 5.4, 5.7, 6, 6.3, 6.6, 6.9, 7.2, 7.5, 7.8, 8.1, 8.4, 8.7, 9, 9.3, 9.6, 9.9

Εξαγωγή στο Πρόχειρο

Ο κώδικας για να μας κάνει εξαγωγή τα παραπάνω νούμερα στο πρόχειρο είναι αυτός:
Έγγραφο Ν$="1.5"
Για ι=1.8 έως 10 ανά .3 {
     Ν$=", "+Γραφη$(ι,"")
}
Πρόχειρο Ν$


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


Αλφαριθμητικά Πολλαπλών Παραγράφων



\\ μπορούμε να δίνουμε αλφαριθμητικά πολλαπλών γραμμών
\\ η θέση του τελευταίου άγκιστρου δηλώνει πόσα κενά θα αφαιρεθούν
\\ από την δεύτερη παράγραφο και κάτω

Ν$={Κείμενο, Πρώτη παράγραφος
      Δεύτερη παράγραφος
      Τρίτη παράγραφος
      }
Αναφορά Ν$
Έγγραφο Ν$ ' αναβάθμιση σε Έγγραφο
Αναφορά Παραγραφος$(Ν$, 2)
Αναφορά Παραγραφος$(Ν$, 1)
\\ Αφαιρούμε τη δεύτερη παράγραφο
\\ ενώ μας την δίνει σε μια μεταβλητή αλφαριθμητική
παλιάπαράγραφος$=Παράγραφος$(Ν$,2,-1)
Αναφορά Ν$
\\ βάζουμε και μια αλλαγή γραμμής
Ν$=παλιάπαράγραφος$+{
}
Ν$=παλιάπαράγραφος$
Αναφορά Ν$


Μορφή Για/Επομενο

Για ι=10 έως 1 ανά 2
      Τύπωσε ι,
Επόμενο ι
Τύπωσε
Υπάρχει και η μορφή που ταιριάζει με την Basic (αλλά και εδώ τα όρια δηλώνουν την κατεύθυνση της μέτρησης, ενώ στην Basic πρέπει να δοθεί αρνητικό βήμα. Αν δώσουμε και εδώ -2, ο διερμηνευτής θα εξάγει το απόλυτο νούμερο (χωρίς το πρόσημο). Χρησιμοποιεί το πρόσημο μόνο αν έχουμε ίσα όρια.

Χρήση συνθήκης για επανάληψη με την Ενώ

Στην Ενώ συνθήκη { } υπάρχει περίπτωση να μην εκτελεστεί ποτέ το μπλοκ. Αυτό συμβαίνει αν δεν γίνει η συνθήκη αληθής.


Κ=3
Ενώ Κ<10 {
      Τύπωσε Κ
      Κ++
}


Λ=5
Κ=3
Ενώ Κ<10 και Λ>3 {
      Τύπωσε Κ
      Κ++
      Λ-=.8
}

στις νέες εκδόσεις οι αγκύλες μπορούν να φύγουν (μπαίνει το Τέλος Ενώ.:

Λ=5
Κ=3
Ενώ Κ<10 και Λ>3
      Τύπωσε Κ
      Κ++
      Λ-=.8
Τέλος Ενώ


Οι πράξεις γίνονται με πραγματικούς αριθμούς, ακόμα και αν βάλουμε μεταβλητή ακέραια (με % στο όνομα). Αποθηκεύονται τα αποτελέσματα ως ακέραια μόνο αν τα καταχωρούμε σε ακέραιες μεταβλητές ή τα περάσουμε από την Ακ()


Χρήση συνθήκης για επανάληψη τύπου Επανέλαβε/Μέχρι



Δ=0
Α=-10
Επανέλαβε {
      Α++
      Δ=Τυχαίος(1,5)
      Τύπωσε Α*Δ,
} Μέχρι Α>5 ή Δ=3
Τύπωσε


Η εντολή Επανέλαβε υπάρχει και σαν Επανάλαβε

Χρήση Αν συνθήκης Τότε σε επανάληψη τύπου Επανέλαβε/Πάντα



Δ=0
Α=-10
Επανέλαβε {
      Α++
      Δ=Τυχαίος(1,5)
      Αν Δ=3 Τότε Έξοδος
      Τύπωσε Α*Δ,
      Αν Α>5 Τότε Έξοδος
} Πάντα
Τύπωσε


Στις νέες εκδόσεις υπάρχει η Επανέλαβε Όσο (Υπάρχει και η Επανάλαβε σε όλες τις περιπτώσεις, επειδή κάποιοι το χρησιμοποιούν πιο εύκολα):

Δ=0
Α=-10
Επανέλαβε {
      Α++
      Δ=Τυχαίος(1,5)
      Αν Δ=3 Τότε Έξοδος
      Τύπωσε Α*Δ,
} όσο Δ<6
Τύπωσε

Επίσης οι αγγύλες μπορούν να φύγουν

Δ=0
Α=-10
Επανέλαβε
      Α++
      Δ=Τυχαίος(1,5)
      Αν Δ=3 Τότε Έξοδος
      Τύπωσε Α*Δ,
Όσο Δ<6
Τύπωσε

Συνοψίζοντας έχουμε την Ενώ με συνθήκη στην αρχή, και την Επανέλαβε/Επανάλαβε με τρείς παραλλαγές Μέχρι, Όσο και Πάντα. Η Όσο είναι η Μέχρι Όχι ( συνθήκη)

Χρήση Τυχαίων με πρόσκαιρη δημιουργία τυχαίων βάσει μιας αρχής.



Με την εντολή Ν=Τυχαίος(!4567) θέτουμε τη γεννήτρια τυχαίων αριθμών από ένα σημείο που θα δώσει την ίδια σειρά αριθμών. Υπάρχει η δυνατότητα να κόψουμε πρόσκαιρα τη ροή τυχαίων, να τη βάλουμε σε μια ροή γνωστή και να γυρίσουμε στην προηγούμενη ροή (δεν κρατάει πάνω από ένα κόψιμο το σύστημα).


Το παρακάτω πρόγραμμα δίνει τρεις τυχαίους, μετά άλλους τρεις που ξεκινούν από καθορισμένο σημείο και μετά συνεχίζει από το προηγούμενο.
Το δεύτερο μέρος είναι οι αριθμοί χωρίς τους ενδιάμεσους τρεις:


Ν=Τυχαίος(!1983874)
Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος
Ν=Τυχαίος(!19742323)
Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος
Ν=Τυχαίος(!)
Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος

\\ χωρίς την προσωρινή αλλαγή
Ν=Τυχαίος(!1983874)
Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος
\\Ν=Τυχαίος(!19742323)
\\Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος
\\Ν=Τυχαίος(!)
Τύπωσε Τυχαίος, Τυχαίος, Τυχαίος


Η Τυχαίος δίνει έναν δεκαδικό αριθμό μη μηδενικό ακέραιο μέρος, ενώ η Τυχαίος(1, 5) θα δώσει έναν από τους 1,2,3,4,5. Αν δώσουμε τιμές με δεκαδικά στην Τυχαίος() αυτή θα πάρει τις τιμές ως ακέραιους (θα εκτελέσει το Ακ() εσωτερικά).

Γέμισμα πίνακα με τυχαίους αριθμούς και μέτρηση συχν. Εμφάνισης


Θα γεμίσουμε έναν πίνακα με τιμές από 1 έως 8 και θα μετρήσουμε πόσες φορές κάθε νούμερο υπάρχει στο πίνακα. Η συχνότητα εμφάνισης είναι ο λόγος πόσες φορές εμφανίζεται στο σύνολο των αριθμών (μέτρηση για το καθένα ξεχωριστό αριθμό προς συνολικό αριθμό)
Στο παράδειγμα ορίζουμε ότι η βάση των πινάκων θα είναι το 0 (Αυτό είναι εξ ορισμού). Μπορούμε όμως να ορίσουμε κάποιο πίνακα με βάση το 1 ειδικά για αυτόν (ομοίως αν είχαμε το 1 για όλους τους πίνακες).
Το γέμισμα του πίνακα γίνεται με το τελεστή << ο οποίος εκτελείται για κάθε στοιχείο, εδώ εκτελούμε την Τυχαίος(1,8) για κάθε στοιχείο.
Η μεταβλητή Ν κρατάει το νούμερο στοιχείων. Όσο μεγαλύτερη είναι η Ν τόσο στρώνουν οι συχνότητες.
Εδώ στο παράδειγμα ξεκινάμε με Ν=20000, δηλαδή θα φτιάξουμε έναν πίνακα με 20 χιλιάδες αριθμούς (η μνήμη που θα χρειαστεί είναι 12*20000 ή 234,375 kBytes). Κανονικά ο double θέλει 8 Bytes αλλά οι πίνακες της Μ2000 κρατούν εσωτερικά Variant (12 Bytes), για σκοπό που δεν γίνεται τώρα φανερός!
Βάση 0
Ν=20000
Πίνακας Α(Ν)<<Τυχαίος(1,8)
Πίνακας Βάση 1, Μετρ(8)
Για ι=0 έως Ν-1 {
      Μετρ(Α(ι))++
}
Για ι=1 έως 8 {
      Τύπωσε Μορφή$("Το {0} έχει συχνότητα {1:2}%",ι,Μετρ(ι)/Ν*100)
}

Ο τελεστής ++ αυξάνει κατά ένα το στοιχείο Α(ι) του πίνακα Μετρ(). Ξέρουμε ότι οι τιμές στον Α(ι) είναι από 1 έως 8, οπότε δεν θα προκύψει λάθος δείκτη. Η Μ2000 ελέγχει κάθε φορά αν ο δείκτης είναι εκτός ορίων.

H M2000 χρησιμοποιεί αυτόν τον αλγόριθμο: https://en.wikipedia.org/wiki/Wichmann–Hill
Η συχνότητα όσο μεγαλώνουμε το Ν (πχ αν το κάνουμε 200000, δεκαπλάσιο δηλαδή), θα πλησιάζει το 12.5 (είτε από πάνω είτε από κάτω), ενώ σε μικρό Ν θα έχουμε μεγάλες αποκλίσεις. Δοκιμάστε με Ν=200.


Πίνακας Τριών διαστάσεων με ένα μόνο στοιχείο!


Οι διαστάσεις σε έναν πίνακα μπορεί να είναι από μηδέν (κενός πίνακας) έως και δέκα. Για κάθε διάσταση από ένα μέχρι δέκα ορίζεται ο αριθμός δεικτών (όχι στοιχείων, μόνο στους μονοδιάστατους ταυτίζεται ο αριθμός αυτός με τον αριθμό στοιχείων). Ουσιαστικά οι διαστάσεις είναι ο τρόπος "διευθυνσιοδότησης", ή οι απαιτούμενοι διαφορετικοί δείκτες για να φέρουν ένα στοιχείο, είτε για να το διαβάσουμε είτε για να το γράψουμε. 

Στις νέες εκδόσεις:
α) Μπορούμε να ορίσουμε περιοχή πχ Πίνακας Α(-5 έως 5, -2 έως 4)  (φτιάχνει πίνακα Α(11,7) αλλά αντί να ξεκινάει από 0 και 0 και να φθάνει το 10 και 6, με βάση το 0, έχει διαφετική βάση σε κάθε διάσταση, στη πρώτη το -5 και στη δεύτερη το -2, άρα έχουμε από Α(-5,-2) μέχρι Α(5, 4), και το Α(0,0) υπάρχει!
β) Μπορούμε να έχουμε δείκτη σε πίνακα. πχ το Α=Α() κάνει το Α δείκτη σε πίνακα και το Α+=10 αυξάνει όλα τα στοιχεία με το 10, ενώ το Α#Αθρ() δίνει το άθροισμα όλων των αριθμών στο πίνακα (ενδέχεται ο πίνακας να έχει στοιχεία διαφετικά, δηλαδή και αριθμούς και γράμματα-αλφαριθμητικά).
γ) Αυτόματοι πίνακες (tuple). Τύπωσε (1,2,3,4)#αθρ() δίνει το 10, και το (1,2,3,4) λέγεται αυτόματος πίνακας επειδή δημιουργείται χωρίς την Πίνακας, ή την Τοπικός (φτιάχνει τοπικούς πίνακες) ή την Γενικός (φτιάχνει γενικούς πίνακες). Η Πίνακας ενδέχεται να μην φτιάξει τοπικό αν υπάρχει ήδη γενικός, δηλαδή απλά κάνει επανακαθορισμό των διαστάσεων/αριθμών στοιχείων. Η τοπικός (local) και γενικός (global), πάντα δημιουργούν νέο πίνακα, και δεν τον βάζουμε σε επανάληψη γιατί θα φτιάχνει συνέχεια νέους που θα σκιάζουν τους παλιούς, και θα είναι άσκοπη σπατάλη μνήμης.
δ) Οι πίνακες με παρενθέσεις όπως το Α() έχουν την ιδιότητα να αντιγράφονται με ρηχή αντιγραφή σε περίπτωση που κάποια στοιχεία είναι δείκτες σε αντικείμενα. Στις περιπτώσεις των Ομάδων (τα αντικείμενα που ορίζουμε εμείς) αν είναι με μοναδικό δείκτη τότε αυτά αντιγράφονται, αλλά αν είναι με δείκτη έναν από τους πολλούς, τότε αντιγράφεται μόνο ο δείκτης (και στη περίπτωση αυτή ο αριθμός δεικτών καταγράφεται στο αντικείμενο, και η ζωή του τερματίζει όταν διαγραφεί και ο τελευταίος προς αυτόν δείκτης).

Μπορούμε να φτιάξουμε έναν πίνακα τριών διαστάσεων με ένα μόνο στοιχείο!
Πίνακας Βάση 1, Μ(1,1,1)=5
Τύπωσε Μήκος(Μ()) \\ 1
Τύπωσε Μ(1,1,1) \\ 5
\\ αλλάζουμε βάση χωρίς να σβήσουμε περιεχόμενα
Πίνακας Βάση 0, Μ(1,1,1)
Τύπωσε Μήκος(Μ()) \\ 1
Τύπωσε Μ(0,0,0) \\ 5
\\ Αλλάζουμε διάσταση χωρίς να σβήσουμε περιεχόμενα
Πίνακας Μ(1)
Τύπωσε Μήκος(Μ()) \\ 1
Τύπωσε Μ(0) \\ 5



Τμήμα Τμήμα1 {
Κλάση Αλφα {
χ, ψ
διαγραφή {
Τύπωσε "Το αντικείμενο τύπου Αλφα διαγράφτηκε με τιμές:", ,
}
Κλάση:
Τμήμα Αλφα(.χ, .ψ) {
}
}
Πίνακας Α(3), Β()
Α(0)=Αλφα(10, 20)
// ο Μ έγινε δείκτης στο Α(0), άρα ο Α(0) έχει το ίδιο αντικείμενο με το Μ
// άρα το αντικείμενο δεν έχει πια μοναδικό δείκτη!
Μ->Α(0)
Α(1)=Αλφα(10, 20)
// το Α(2) έχει δείκτη σε αντικείμενο. Τώρα είναι μόνο ένας, αλλά δεν είναι "μοναδικός"
// δηλαδή είναι δείκτης σε αντικείμενο όπως ο Μ και ο Α(0)
Α(2)->Αλφα(10, 20)
Β()=Α()
Β(1).χ=100 : Β(1).ψ=500
Β(2).χ=1000 : Β(2).ψ=5000
Β(0).χ=10000 : Β(0).ψ=50000

Τύπωσε Α(1).χ=10, Β(1).χ=100
// εδώ το Α(1)  δίνει αντίγραφο
Τύπωσε Α(1) είναι Β(1) = ψευδής
// και διαγράφεται με το πέρας εκτέλεσης της λογικής έκφρασης
Τύπωσε Α(2).χ=1000, Β(2).χ=1000
Τύπωσε Α(2) είναι Β(2) = αληθής
Τύπωσε Α(0).χ=10000, Β(0).χ=10000
Τύπωσε Α(0) είναι Β(0) = αληθής
ΈλεγχοςΔείκτη(0, Α(0))
ΈλεγχοςΔείκτη(2, Α(2))
Δες οκ {
// και πάλι εδώ έχουμε δημιουργία αντιγράφου από το Α(1)
ΈλεγχοςΔείκτη(1, Α(1))
// οπότε θα δούμε διαγραφή αντικειμένου
}
Τύπωσε Λάθος, οκ=ψευδής, λάθος$=" λάθος τύπος αντικειμένου"

Για ι=0 έως 2
Δες οκ {
ΈλεγχοςΟμάδας(ι, Α(ι))
}
// δεν έχουμε λάθος εδώ
Επόμενο
Για ι=0 έως 2
δες Οκ {
// στο μπλοκ εκτελούμε σαν μια μέθοδο του αντικειμένου, με όνομα όμως το ίδιο με τους τμήματος
// οπότε έχουμε το ίδιο "όνομα χώρου"
// ότι φτιάχνουμε όμως εδώ θα καθαρίσει!
// υπάρχει η Για Αυτό  { } που μέσα σε ένα τμήμα (που δεν είναι μέθοδος αντικειμένου)
// ανοίγει ένα μπλοκ για προσωρινούς ορισμούς
// (θα σβήσουν στην εξοδο από το μπλοκ, κανονκά στο τέλος ή με Έξοδο/Προς από οπουδήποτε)
Για Α(ι) {
// στειλαμε το Αυτό
ΈλεγχοςΟμάδας2(ι, &Αυτό)
}
}
Επόμενο
// αν έχουμε δείκτη μπορούμε να χρησιμοποιήσουμε αυτό => αντί για τελεία
// στις μεταβλητές με δείκτη είναι υποχρεωτικό.
// Όπου όμως δεν έχουμε δείκτη, το => βγάζει λάθος.
Για ι=0 έως 2
// και εδώ έχουμε αντιγραφή αντικειμένου στο Α(ι), όταν το ι=1, όπου δίνει 0 η συνάρτηση Έγκυρο()
Αν Έγκυρο(Α(ι)=>χ) Τότε Τύπωσε "Α(";ι;")=>χ=";Α(ι)=>χ
Τύπωσε "Α(";ι;").χ=";Α(ι).χ
Επόμενο
// στο τέλος θα καθαρίσουν 4 αντικείμενα, τρια στο πίνακα Α() και ένα στο Β(1) (τα Β(0) και Β(2) δείχνουν τα αντίστοιχα Α(0) και Α(2))
Τύπωσε "Τέλος"
Τέλος


Ρουτίνα ΈλεγχοςΔείκτη(κ, μ ως *Αλφα)
Τύπωσε κ, μ=>χ, μ=>ψ, μ είναι τύπος Αλφα
Τέλος Ρουτίνας
Ρουτίνα ΈλεγχοςΟμάδας(κ, μ)
Τύπωσε "ΈλεγχοςΟμάδας(κ, μ)"
Αν Έγκυρο(μ=>χ) τότε
μ=>χ++
// πέρασμα δείκτη σημαίνει ότι αν και πέρασμα με τιμή είναι "σαν" πέρασμα με αναφορά
// αφού αλλάζουμε τα στοιχεία.
// αυτό που δεν αλλάζουμε είναι ο δείκτης.
Τύπωσε κ, μ=>χ, μ=>ψ, τύπος$(μ)="Group", " Δείκτης σε Ομάδα"
Αλλιώς
Τύπωσε κ, μ.χ, μ.ψ, τύπος$(μ)="Group", " Ομάδα"
Τέλος αν
Τύπωσε μ είναι τύπος Αλφα = Αληθής
Τέλος Ρουτίνας
Ρουτίνα ΈλεγχοςΟμάδας2(κ, ως Ομάδα)
Αν μ είναι τύπος Αλφα τότε
μ.χ++
Τύπωσε μ.χ, μ.ψ, τύπος$(μ)="Group"
Αλλιώς
Τύπωσε "λάθος τύπος"
Τέλος Αν
Τέλος Ρουτίνας
}
Τμήμα1  // εδώ καλούμε το τμήμα Τμήμα1





Παρασκευή 28 Απριλίου 2017

Επικαιροποίηση του Μικρού Εγχειριδίου της Μ2000

Ενημερώθηκε το μικρό εγχειρίδιο της Μ2000. Περιλαμβάνει νέα παραδείγματα και σημειώσεις συνοπτικές για γνώστες γλωσσών.

ο σύνδεσμος βρίσκεται στην στήλη δεξιά

και εδώ