Διανύσματα στις 3 Διαστάσεις

Σχετικά έγγραφα
Εντολές εισόδου - εξόδου. Εισαγωγή στη C++

Αντικειμενοστραφείς Γλώσσες Προγραμματισμού C++ / ROOT

κεφάλαιο Συναρτήσεις ΙII

Προγραμματισμός και Χρήση Ηλεκτρονικών Υπολογιστών - Βασικά Εργαλεία Λογισμικού

Προγραμματισμός Υπολογιστών με C++

Εισαγωγή στον Προγραμματισμό

Πληροφορική 2. Γλώσσες Προγραμματισμού

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τύποι δεδομένων ΤΥΠΟΙ ΔΕΔΟΜΕΝΩΝ ΠΡΑΞΕΙΣ ΜΕΤΑΒΛΗΤΕΣ. Ακέραιοι αριθμοί (int) Πράξεις μεταξύ ακεραίων αριθμών

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις I Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Τύποι δεδομένων, μεταβλητές, πράξεις. Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Τελεστές ΤΕΛΕΣΤΕΣ. Γεώργιος Παπαϊωάννου ( )

Υπερφόρτωση τελεστών

Στοιχειώδης προγραμματισμός σε C++

Προγραμματισμός Υπολογιστών με C++

Δομή Προγράμματος C++, Χειρισμός Μεταβλητών και Συναρτήσεις Εισόδου - Εξόδου

Προγραμματισμός Ι. Κλάσεις και Αντικείμενα. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Κλήση Συναρτήσεων ΚΛΗΣΗ ΣΥΝΑΡΤΗΣΕΩΝ. Γεώργιος Παπαϊωάννου ( )

lab2 -Στην printf να βάζεις \n έτσι ώστε να αλλάζει γραµµή όποτε σου εµφανίζει κάποιο µήνυµα.

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι περιλαμβάνει μια μεταβλητή; ΔΕΙΚΤΕΣ. Διεύθυνση μεταβλητής. Δείκτης

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Εντολές for, while, do-while Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

ΕΝΝΟΙΑ ΤΟΥ ΜΙΓΑΔΙΚΟΥ ΑΡΙΘΜΟΥ ΠΡΑΞΕΙΣ ΣΤΟ ΣΥΝΟΛΟ ΤΩΝ ΜΙΓΑΔΙΚΩΝ

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δομή του προγράμματος. Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

ΒΑΣΙΚΟΙ ΤΥΠΟΙ ΚΑΙ ΠΙΝΑΚΕΣ

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δομές Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Συστήματα συντεταγμένων

ΜΑΘΗΜΑΤΑ ΜΑΘΗΜΑΤΙΚΑ ΘΕΤΙΚΟΥ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΥ Β ΛΥΚΕΙΟΥ

Προγραμματισμός Ι. Δείκτες. Δημήτρης Μιχαήλ. Τμήμα Πληροφορικής και Τηλεματικής Χαροκόπειο Πανεπιστήμιο

Τάξη B. Μάθημα: Η Θεωρία σε Ερωτήσεις. Επαναληπτικά Θέματα. Επαναληπτικά Διαγωνίσματα. Επιμέλεια: Κώστας Κουτσοβασίλης. α Ε

Ονοματεπώνυμο και ΑΜ: Είχα παραδώσει εργασίες τα προηγούμενα ακαδημαϊκά έτη: ΚΑΛΗ ΕΠΙΤΥΧΙΑ!

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Εντολή if. Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Πίνακες (Arrays) Εισαγωγή στη C++

Εισαγωγή στον Προγραμματισμό με C++

Δισδιάστατοι Πίνακες (2D Arrays) Εισαγωγή στη C++

Προγραμματισμός Υπολογιστών με C++

Υπολογιστικά Mαθηματικά II

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι είναι ; Συναρτήσεις. Παράδειγμα #1. double convert ( double cm ) { double inch;

Δομές δεδομένων (Structures) Εισαγωγή στη C++

Εισαγωγή στη γλώσσα προγραμματισμού C++

ΘΕΜΑΤΑ ΠΡΟΑΓΩΓΙΚΩΝ ΑΠΟΛΥΤΗΡΙΩΝ ΕΞΕΤΑΣΕΩΝ ΜΑΪΟΣ ΙΟΥΝΙΟΣ

ΥΠΟΛΟΓΙΣΤΕΣ ΙΙ. Τι είναι οι πίνακες; Μονοδιάστατοι πίνακες. Απλές μεταβλητές: Κεντρική μνήμη

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Συναρτήσεις II Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Μαθηματικά Γ Γυμνασίου. Επαναληπτικές Ασκήσεις στο Κεφάλαιο 1: Μονώνυμα - Πολυώνυμα - Ταυτότητες

Αναφορές, είκτες και Αλφαριθμητικά

ΕΠΑΝΑΛΗΨΗ ΜΑΘΗΜΑΤΙΚΑ ΚΑΤΕΥΘΥΝΣΗΣ Β ΛΥΚΕΙΟΥ ( α μέρος )

3 η Διάλεξη C++ - Βασικοί τύποι δεδομένων. Δρ. Χρήστος Δρόσος ΑΕΙ ΠΕΙΡΑΙΑ ΤΤ ΤΜΗΜΑ ΑΥΤΟΜΑΤΙΣΜΟΥ

Η * Η

Προγραμματισμός Υπολογιστών με C++

Ονοματεπώνυμο και ΑΜ: Είχα παραδώσει εργασίες τα εξής ακαδημαϊκά έτη: Διάρκεια: 2,5 ώρες, κλειστά βιβλία και σημειώσεις ΚΑΛΗ ΕΠΙΤΥΧΙΑ!

Δομημένος Προγραμματισμός (ΤΛ1006)

Προγραμματισμός Η/Υ (ΤΛ2007 )

ΟΝΤΟΚΕΝΤΡΙΚΟΣ ΠΡΟΓΡ/ΣΜΟΣ C++

Περιεχόμενα: Prj05.1 Το Πρόβλημα Prj05.2 Παίρνοντας Ιδέες από την Pascal Prj05.3 Η Κλάση και οι Μέθοδοι Prj05.3.

Δομημένος Προγραμματισμός (ΤΛ1006)

Χωρική Βάση δεδοµένων Autocad

Πολλαπλασιασμός αριθμού με διάνυσμα

Εισαγωγή στη γλώσσα προγραμματισμού C++

2 η Διάλεξη C++ Δρ. Χρήστος Δρόσος ΑΕΙ ΠΕΙΡΑΙΑ ΤΤ ΤΜΗΜΑ ΑΥΤΟΜΑΤΙΣΜΟΥ

( ) ( ) ( )z. HMY Φωτονική. Διάλεξη 08 Οι εξισώσεις του Maxwell. r = A r. B r. ˆ det = Βαθμωτά και διανυσματικά μεγέθη

Α' Εξάμηνο ΕΙΣΑΓΩΓΗ ΣΤΟ ΔΟΜΗΜΕΝΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ

Προγραμματισμός Υπολογιστών με C++

Η εντολή if-else. Η απλή μορφή της εντολής if είναι η ακόλουθη: if (συνθήκη) { Η γενική μορφή της εντολής ifelse. εντολή_1; εντολή_2;..

* Το Σωστό Πρόγραμμα. κεφάλαιο

Συναρτήσεις (Functions) Εισαγωγή στη C++

Πληροφορική 2. Αλγόριθμοι

1 η Εργασία Ηµεροµηνία αποστολής: 19 Νοεµβρίου 2006

3.1 Αριθμητικοί και Λογικοί Τελεστές, Μετατροπές Τύπου (Casting)

Γλώσσα Προγραμματισμού C++ Εισαγωγή - Μια πρώτη ματιά

ΥΠΟΛΟΓΙΣΤΕΣ ΙI. Άδειες Χρήσης. Δείκτες Διδάσκοντες: Αν. Καθ. Δ. Παπαγεωργίου, Αν. Καθ. Ε. Λοιδωρίκης

Γ7.1 Επανάληψη ύλης Β Λυκείου. Γ Λυκείου Κατεύθυνσης

ΤΡΑΠΕΖΑ ΘΕΜΑΤΩΝ ΤΩΝ ΜΑΘΗΜΑΤΙΚΩΝ ΘΕΤΙΚΟΥ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΥ ΤΗΣ Β ΛΥΚΕΙΟΥ

Προγραμματισμός Υπολογιστών με C++

Τίτλος Μαθήματος: Ηλεκτρονικοί Υπολογιστές IΙΙ. Διδάσκων: Επίκουρος Καθηγητής Αθανάσιος Σταυρακούδης

ΜΑΘΗΜΑΤΙΚΑ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΥ

π (α,β). Έστω τα διανύσματα π (α,β) να βρεθούν:

Προγραμματισμός Υπολογιστών με C++

Ελληνική Δημοκρατία Τεχνολογικό Εκπαιδευτικό Ίδρυμα Ηπείρου. Πληροφορική II. Ενότητα 3 : Γλώσσες προγραμματισμού. Δρ.

Μαθηματικά Γ Γυμνασίου. Επαναληπτικές Ασκήσεις στο Κεφάλαιο 1: Μονώνυμα - Πολυώνυμα - Ταυτότητες

ΚΥΚΛΟΣ. Μ(x,y) Ο C ΘΕΩΡΙΑ ΕΠΙΜΕΛΕΙΑ: ΣΩΣΤΟ-ΛΑΘΟΣ ΠΟΛΛΑΠΛΗΣ ΕΠΙΛΟΓΗΣ ΧΡΑΣ ΓΙΑΝΝΗΣ ΑΣΚΗΣΕΙΣ. 3ο ΓΕΝΙΚΟ ΛΥΚΕΙΟ ΚΕΝΤΡΙΚΟ Ν. ΣΜΥΡΝΗΣ

ΣΥΣΤΗΜΑΤΑ. 6.1 ΓΡΑΜΜΙΚΑ ΣΥΣΤΗΜΑΤΑ (Επαναλήψεις-Συμπληρώσεις)

1 ΘΕΩΡΙΑΣ...με απάντηση

n, C n, διανύσματα στο χώρο Εισαγωγή

Κεφάλαιο 4: Συνθήκες Έλεγχου (if-else, switch) και Λογικοί τελεστές / παραστάσεις. (Διάλεξη 8)

ΜΑΘΗΜΑΤΙΚΑ - Γ ΓΥΜΝΑΣΙΟΥ

Προγραμματισμός Υπολογιστών με C++

ΕΥΘΕΙΑ. Κεφάλαιο 2ο: Ερωτήσεις του τύπου «Σωστό-Λάθος»

ΜΑΘΗΜΑΤΙΚΑ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΥ

Διανύσματα 1. Διανύσματα Πρόσθεση Διανυσμάτων Φυσική ποσότητα που περιγράφεται μόνο από ένα αριθμό ονομάζεται βαθμωτή.

Α' Εξάμηνο ΕΙΣΑΓΩΓΗ ΣΤΟ ΔΟΜΗΜΕΝΟ ΠΡΟΓΡΑΜΜΑΤΙΣΜΟ

Εφαρμοσμένα Μαθηματικά ΙΙ

Οντοκεντρικός Προγραμματισμός

1 ΔΙΑΓΩΝΙΣΜΑΤΑ ΠΡΟΑΓΩΓΙΚΩΝ ΕΞΕΤΑΣΕΩΝ ΛΥΚΕΙΩΝ ΤΗΣ ΡΟΔΟΥ ΤΗΣ Β ΤΑΞΗΣ ΣΤΑ ΜΑΘΗΜΑΤΙΚΑ ΚΑΤΕΥΘΥΝΣΗΣ. α. Τι ονομάζουμε εσωτερικό γινόμενο δύο διανυσμάτων, β

1,y 1) είναι η C : xx yy 0.

Φυσική για Μηχανικούς

ΤΡΑΠΕΖΑ ΘΕΜΑΤΩΝ ΤΩΝ ΜΑΘΗΜΑΤΙΚΩΝ ΘΕΤΙΚΟΥ ΠΡΟΣΑΝΑΤΟΛΙΣΜΟΥ ΤΗΣ Β ΛΥΚΕΙΟΥ

Εισαγωγή στον Προγραμματισμό

Συμβολοσειρές ΣΥΜΒΟΛΟΣΕΙΡΕΣ. Γεώργιος Παπαϊωάννου ( )

. Μονάδες 3 β) Τα διανύσματα και. τότε x1x2 y1y2. είναι κάθετα αν και μόνο αν 0 Μονάδες 3 γ) Το διάνυσμα,

ΨΗΦΙΑΚΑ ΗΛΕΚΤΡΟΝΙΚΑ. ιδάσκων : ρ. Β. ΒΑΛΑΜΟΝΤΕΣ. Πύλες - Άλγεβρα Boole 1

x y z xy yz zx, να αποδείξετε ότι x=y=z.

Δομημένος Προγραμματισμός. Τμήμα Επιχειρηματικού Σχεδιασμού και Πληροφοριακών Συστημάτων

Transcript:

project 2 Διανύσματα στις 3 Διαστάσεις Περιεχόμενα: Prj02.1 Το Πρόβλημα... 485 Prj02.2 Ο Τύπος Vector3 και οι Δημιουργοί... 486 Prj02.3 Οι Τελεστές Σύγκρισης... 487 Prj02.4 Οι Τελεστές +, -, *, ^... 488 Prj02.5 Ο Ενικός Τελεστής -... 489 Prj02.6 Οι Τελεστές Εκχώρησης... 489 Prj02.7 Ο Τελεστής <<... 490 Prj02.8... και το Ευκλείδιο Μέτρο... 490 Prj02.9 Το Πρόγραμμα... 490 Prj02.1 Το Πρόβλημα Το Project αυτό είναι ένα μεγάλο παράδειγμα επιφόρτωσης τελεστών. Είναι καλό να το διαβάσεις προσεκτικά διότι αργότερα θα το ξαναδούμε και θα αλλάξουμε μερικά από αυτά πόυ θα δούμε εδώ. Ένα τρισδιάστατο (ελεύθερο) διάνυσμα (vector) είναι μια διαταγμένη τριάδα πραγματικών αριθμών (x, y, z). Όρισε έναν τύπο δομής Vector3 που τα αντικείμενά της θα είναι διανύσματα του χώρου τριών διαστάσεων. Όρισε έναν ερήμην δημιουργό που θα μας δίνει ελεύθερο διάνυσμα με συνιστώσες (0, 0, 0) αλλά θα μπορεί να πάρει και αρχικές τιμές των συνιστωσών. A. Έστω ότι έχουμε δύο διανύσματα v1 = (x1, y1, z1) και v2 = (x2, y2, z2). 1. Τα v1 και v2 μπορεί να συγκριθούν για ισότητα και μόνον (δηλαδή έχουν νόημα μόνον οι == και!= ). Είναι ίσα αν και μόνον αν x1 = x2 y1 = y2 z1 = z2. Επιφόρτωσε τους τελεστές σύγκρισης == και!= για τον Vector3. 2. Μπορούμε ακόμη να τα προσθέσουμε ή τα αφαιρέσουμε και να πάρουμε ένα διάνυσμα v1 ± v2 με συνιστώσες (x1±x2, y1±y2, z1±z2). Επιφόρτωσε τους τελεστές + και - για τον Vector3. Επιφόρτωσε τους τελεστές += και -= για τον Vector3. 3. Πολλαπλασιάζοντας ένα διάνυσμα v1 επί έναν πραγματικό αριθμό α (αv1 ή v1α) παίρνουμε ένα νέο διάνυσμα με συνιστώσες (αx1, αy1, αz1). Επιφόρτωσε καταλλήλως τον τελεστή * για τον Vector3. Επιφόρτωσε τον τελεστή *= για τον Vector3. 4. Ειδική περίπτωση: το ( 1)v1 μπορεί να γραφεί και ως v1. Επιφόρτωσε καταλλήλως τον ενικό τελεστή - για τον Vector3. 485

486 Project 02 5. Μπορούμε να πολλαπλασιάσουμε τα v1 και v2 και να πάρουμε τον πραγματικό αριθμό: v1 v2 = x1x2 + y1y2 +z1z2 που λέγεται εσωτερικό γινόμενο (inner ή dot product). Επιφόρτωσε (άλλη μια φορά) καταλλήλως τον τελεστή * για τον Vector3. 6. Μπορούμε όμως να πάρουμε και το εξωτερικό γινόμενο (outer ή cross product) v1 v2 που είναι διάνυσμα: v1 v2 = (y1z2-z1y2, x2z1-z2x1, y2x1-x2y1). Επιφόρτωσε καταλλήλως τον τελεστή ^ για τον Vector3 ώστε να υπολογίζει το εξωτερικό γινόμενο. 7. Καλό θα είναι να μπορούμε να γράψουμε στην οθόνη ή σε ένα αρχείο text την τιμή του διανύσματος με τον <<. Επιφόρτωσε τον << για αντικείμενα τύπου Vector3. 8. Τέλος, για κάθε διάνυσμα ορίζεται ένα ευκλείδιο μέτρο: v = v v ) που είναι το μήκος του διανύσματος. Γράψε συνάρτηση Vector3_abs που να δίνει το ευκλείδιο μέτρο ενός αντικειμένου τύπου Vector3. B. Για μια απλή εφαρμογή των παραπάνω, γράψε πρόγραμμα που θα υπολογίζει τη δύναμη Laplace FL = q(v B) που ασκείται σε φορτίο q = 1 μcb που εισέρχεται με ταχύτητα v = (10 8, 0, 0) σε μαγνητικό πεδίο B = (0, 0, 10). Επιβεβαίωσε ότι η δύναμη είναι κάθετη στα v και B (δηλαδή: FL v = 0 και FL B = 0). Το εμβαδόν παραλληλογράμμου που οι πλευρές του είναι παράλληλες προς τα ελεύθερα διανύσματα a και b είναι το διάνυσμα S = a b. Αν έχουμε το παραλληλόγραμμο μέσα σε ένα μαγνητικό πεδίο τότε η μαγνητική ροή που διέρχεται από αυτό είναι ίση με B S. Συμπλήρωσε το πρόγραμμά σου με εντολές που θα υπολογίζουν τη μαγνητική ροή που διέρχεται από παραλληλόγραμμο με πλευρές a = (0.1, 0.2, 0.3) και b = (0.2, 0.3, 0.4) όταν βρίσκεται στο μαγνητικό πεδίο που δώσαμε παραπάνω. Με τα a και b επιβεβαίωσε την ταυτότητα: a 2 b 2 = (a b) 2 + a b 2. x 2 y 2 z 2 (= Prj02.2 Ο Τύπος Vector3 και οι Δημιουργοί Ο τύπος αυτός είναι σαν τον complex αλλά με τρία μέλη: struct Vector3 double x; double y; double z; }; // Vector3 Γράφουμε τον ερήμην δημιουργό με αρχικές τιμές όπως κάναμε και στην complex: Vector3( double ax=0, double ay=0, double az=0 ) x = ax; y = ay; z = az; } Πρόσεξε ότι με αυτόν τον δημιουργό μπορούμε να κάνουμε τις εξής δηλώσεις: Vector3 v0; // (0, 0, 0) Vector3 v1( 1 ); // (1, 0, 0) Vector3 v2( sqrt(2), 3 ); // (1.41421, 3, 0) Vector3 v3( sqrt(3), sqrt(5), 2*sqrt(2) ); // (1.73205, 2.23607, 2.82843) Να λοιπόν ο ορισμός του τύπου μας: struct Vector3 double x; double y; double z; Vector3( double ax=0, double ay=0, double az=0 )

Διανύσματα στις 3 Διαστάσεις 487 x = ax; y = ay; z = az; } }; // Vector3 Prj02.3 Οι Τελεστές Σύγκρισης Σύμφωνα με όσα είπαμε στην 14.6.4, ένας δυαδικός τελεστής ( @ ) επιφορτώνεται με μια συνάρτηση της μορφής: Trv operator@( Tl lhs, Tr rhs ) Για έναν τελεστή σύγκρισης, όπως είναι ο ==, Trv είναι ο bool. Για την περίπτωσή μας Tl και Tr είναι, κατ αρχήν, ο Vector3. Θα μπορούσαμε λοιπόν να γράψουμε: bool operator==( Vector3 lhs, Vector3 rhs ) return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z); } // operator==( Vector3 Αυτή είναι απολύτως σωστή, αλλά, παρ όλα αυτά, θα την αλλάξουμε λιγάκι, ως προς τις παραμέτρους: bool operator==( const Vector3& lhs, const Vector3& rhs ) return (lhs.x == rhs.x) && (lhs.y == rhs.y) && (lhs.z == rhs.z); } // operator==( Vector3 Ποιο είναι το πλεονέκτημα της δεύτερης μορφής; Κάθε φορά που την καλούμε θα περάσουν, ως παράμετροι, δύο βέλη ενώ στην πρώτη μορφή θα περάσουν δυο τιμές Vector3. Σε ψηφιολέξεις αυτό θα μπορούσε να σημαίνει (ενδεικτικώς) 8:48 εξαπλάσιο! Ναι, αλλά το 48 είναι πολύ μικρό για να μας δημιουργήσει πρόβλημα. Υπάρχουν όμως και περιπτώσεις αντικειμένων που μπορεί να είναι πολύ μεγάλα σκέψου, για παράδειγμα, ένα αντικείμενο τύπου string με τιμή το κείμενο ενός βιβλίου 1000 σελίδων. Τα πολύ μεγάλα αντικείμενα δεν τα περνάμε ως παραμέτρους τιμής αλλά ως παραμέτρους αναφοράς με const. Θα χρησιμοποιούμε λοιπόν αυτόν τον τρόπο παντού στις επιφορτώσεις τελεστών για να τον συνηθίσεις(!) Ας έλθουμε τώρα στον!= χρειάζεται να τον γράψουμε; Αφού έχουμε τον == θα μπορούμε να γράφουμε!(a == b) αντί για a!= b. Φυσικά, αλλά γενικώς θα τηρούμε την εξής προγραμματιστική πρακτική: 1 Όταν επιφορτώνουμε έναν τελεστή σύγκρισης @ επιφορτώνουμε και τον αντίθετό του με χρήση του @. Έχουμε λοιπόν: bool operator!=( const Vector3& lhs, const Vector3& rhs ) return!(lhs == rhs); } // operator!=( Vector3 Έτσι, έχουμε και τους δύο τελεστές χωρίς ασυμβατότητες (σίγουρα). Αν θέλεις μπορείς να πας ένα βήμα παραπέρα και να αποφύγεις μια κλήση συνάρτησης: bool operator!=( const Vector3& lhs, const Vector3& rhs ) return (lhs.x!= rhs.x) (lhs.y!= rhs.y) (lhs.z!= rhs.z); } // operator!=( Vector3 Για τελεστές που αυτό το τελευταίο βήμα είναι πιο πολύπλοκο και υπάρχει μεγάλη πιθανότητα λάθους μην το κάνεις. 1 Η σύσταση 36 της (ELLEMTEL 1998) λέει: «When two operators are opposite (such as == and!= ), it is appropriate to define both.»

488 Project 02 Prj02.4 Οι Τελεστές +, -, *, ^ Οι δύο προσθετικοί (δυαδικοί) τελεστές και ο ^ (εξωτερικό γινόμενο) θα επιφορτωθούν με συναρτήσεις της μορφής: Trv operator@( Tl lhs, Tr rhs ) Γι ά τις πράξεις αυτές έχουμε: +: Vector3 Vector3 y Vector3 -: Vector3 Vector3 y Vector3 ^: Vector3 Vector3 y Vector3 Τις θεωρούμε μερικές συναρτήσεις επειδή παίρνουμε υπόψη την περίπτωση υπερχείλησης. Στη συνέχεια, στην υλοποίηση, θα τις χειριστούμε σαν ολικές συναρτήσεις δηλαδή δεν θα ρίχνουμε εξαιρέσεις. Στις περιπτώσεις αυτές Trv, Tl και Tr είναι ο Vector3. Σύμφωνα όμως με αυτά που είπαμε παραπάνω, θα βάλουμε τους Tl και Tr const Vector3&: Vector3 operator+( const Vector3& lhs, const Vector3& rhs ) fv.x = lhs.x + rhs.x; fv.y = lhs.y + rhs.y; fv.z = lhs.z + rhs.z; } // operator+( const Vector3& Vector3 operator-( const Vector3& lhs, const Vector3& rhs ) fv.x = lhs.x - rhs.x; fv.y = lhs.y - rhs.y; fv.z = lhs.z - rhs.z; } // operator-( const Vector3& Vector3 operator^( const Vector3& lhs, const Vector3& rhs ) fv.x = lhs.y*rhs.z - lhs.z*rhs.y; fv.y = rhs.x*lhs.z - rhs.z*lhs.x; fv.z = rhs.y*lhs.x - rhs.x*lhs.y; } // operator^( const Vector3 Σημείωση: Υπάρχει δυαδικός τελεστής ^ στη C++; Ναι, αλλά θα τον μάθουμε αργότερα. Στην 14.6 λέγαμε «Δεν αλλάζουμε το νόημα του τελεστή που επιφορτώνουμε.» Αυτό το σεβόμαστε με την επιφόρτωση που κάνουμε; Όχι, αλλά όπως θα καταλάβεις δεν δημιουργεί οποιαδήποτε σύγχυση. Ο * θέλει να σκεφτούμε κάτι παραπάνω. Αν έχουμε δηλώσει: Vector3 v1, v2; double a; θα πρέπει να μπορούμε να γράψουμε είτε: είτε: v2 = a*v1; v2 = v1*a; Έχουμε δηλαδή δύο περιπτώσεις: *: double Vector3 y Vector3 *: Vector3 double y Vector3 Θα κάνουμε λοιπόν διπλή επιφόρτωση του * :

Διανύσματα στις 3 Διαστάσεις 489 Vector3 operator*( double lhs, const Vector3& rhs ) fv.x = lhs * rhs.x; fv.y = lhs * rhs.y; fv.z = lhs * rhs.z; } // operator* Vector3 operator*( const Vector3& lhs, double rhs ) fv.x = rhs * lhs.x; fv.y = rhs * lhs.y; fv.z = rhs * lhs.z; } // operator* Ο * πρέπει να επιφορτωθεί άλλη μια φορά για το εσωτερικό γινόμενο: *: Vector3 Vector3 y double που υλοποιείται με την double operator*( const Vector3& lhs, const Vector3& rhs ) return lhs.x*rhs.x + lhs.y*rhs.y + lhs.z*rhs.z; } // operator*( const Vector3& Prj02.5 Ο Ενικός Τελεστής - Αν έχουμε δηλώσει: Vector3 v1, v2; και δώσουμε: v2 = -v1; το διάνυσμα v2 είναι το αντίθετο του v1, δηλαδή: v1 + v2 = 0. Για τον - έχουμε: -: Vector3 Vector3 Στην 14.6.4 λέγαμε ότι επιφορτώνουμε έναν προθεματικό ενικό τελεστή @ με μια συνάρτηση Trv operator@( T rhs ) και είδαμε ήδη μια εφαρμογή αυτού του κανόνα στον - για τον complex ( 15.5). Τώρα, Trv και T είναι ο Vector3: Vector3 operator-( const Vector3& rhs ) return Vector3( -rhs.x, -rhs.y, -rhs.z ); } // operator-( const Vector3& Prj02.6 Οι Τελεστές Εκχώρησης 2 Τώρα θα επιφορτώσουμε τους τρεις τελεστές εκχώρησης +=, -=, *= όπως είπαμε στην 14.6.3. Εκεί είδαμε ότι ο += για τον τύπο T επιφορτώνεται ως: T& operator+=( T& lhs, const T& rhs ) Προσεξε ότι ο τύπος της πρώτης παραμέτρου δεν έχει const. Στην περίπτωσή μας T είναι ο Vector3 οπότε έχουμε: Vector3& operator+=( Vector3& lhs, const Vector3& rhs ) 2 Αργότερα θα μάθουμε ότι ο πάγιος τρόπος επιφόρτωσης αυτών των τελεστών είναι διαφορετικός.

490 Project 02 lhs.x += rhs.x; lhs.y += rhs.y; lhs.z += rhs.z; return lhs; } // operator+=( Vector3& Παρομοίως γίνεται η επιφόρτωση και των άλλων δύο τελεστών: Vector3& operator-=( Vector3& lhs, const Vector3& rhs ) lhs.x -= rhs.x; lhs.y -= rhs.y; lhs.z -= rhs.z; return lhs; } // operator-=( const Vector3& Vector3& operator*=( Vector3& lhs, double rhs ) lhs.x *= rhs; lhs.y *= rhs; lhs.z *= rhs; return lhs; } // operator*=( const Vector3& Prj02.7 Ο Τελεστής << Έχουμε ήδη επιφορτώσει τον << για αρκετους τύπους. Αντιγράφοντας σχεδόν την επιφόρτωση για τον τύπο complex ( 15.5) έχουμε: ostream& operator<<( ostream& tout, const Vector3& rhs ) return tout << "(" << rhs.x << ", " << rhs.y << ", " << rhs.z << ")"; } // operator<< Prj02.8... και το Ευκλείδιο Μέτρο Για το ευκλείδιο μέτρο δεν έχουμε κάποιον βολικό (από οπτική άποψη) τελεστή. Θα γράψουμε λοιπόν μια: double Vector3_abs( const Vector3& lhs ) return sqrt( lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z ); } // double Vector3_abs Prj02.9 Το Πρόγραμμα Έχοντας αυτά τα εργαλεία το πρόγραμμα είναι τετριμμένο. Για να διευκολύνουμε το γράψιμο (και για να κάνουμε οικονομία στις πράξεις) της τελευταίας ερώτησης ορίζουμε μια επιπλέον συνάρτηση: double Vector3_abs2( const Vector3& lhs ) return ( lhs.x*lhs.x + lhs.y*lhs.y + lhs.z*lhs.z ); } // double Vector3_abs2 που για ένα διάνυσμα a μας δίνει το a 2. Αυτό που περιμένουμε να δούμε είναι ο μηδενισμός της παράστασης: Vector3_abs2(a)*Vector3_abs2(b) - ((a*b)*(a*b)+vector3_abs2(a^b)) Γράφουμε λοιπόν το πρόγραμμα: #include <iostream> #include <cmath>

Διανύσματα στις 3 Διαστάσεις 491 using namespace std; struct Vector3 double x; double y; double z; Vector3( double ax=0, double ay=0, double az=0 ) x = ax; y = ay; z = az; } Vector3( const Vector3& rhs ) x = rhs.x; y = rhs.y; z = rhs.z; } }; // Vector3 bool operator==( const Vector3& lhs, const Vector3& rhs ); bool operator!=( const Vector3& lhs, const Vector3& rhs ); Vector3 operator-( const Vector3& rhs ); Vector3 operator+( const Vector3& lhs, const Vector3& rhs ); Vector3& operator+=( Vector3& lhs, const Vector3& rhs ); Vector3 operator-( const Vector3& lhs, const Vector3& rhs ); Vector3& operator-=( Vector3& lhs, const Vector3& rhs ); Vector3 operator*( double lhs, const Vector3& rhs ); Vector3 operator*( const Vector3& lhs, double rhs ); Vector3& operator*=( Vector3& lhs, double rhs ); double operator*( const Vector3& lhs, const Vector3& rhs ); Vector3 operator^( const Vector3& lhs, const Vector3& rhs ); ostream& operator<<( ostream& tout, const Vector3& rhs ); double Vector3_abs( const Vector3& lhs ); double Vector3_abs2( const Vector3& lhs ); int main() double q( 1e-6 ); // Cb Vector3 v( 1e8, 0, 0 ); Vector3 B( 0, 0, 10 ); Vector3 FL; FL = q*( v ^ B ); cout << FL << endl; cout << FL*v << " " << FL*B << endl; Vector3 a( 0.1, 0.2, 0.3 ), b( 0.2, 0.3, 0.4 ); cout << a << " " << b << endl; cout << B*( a ^ b) << endl; cout << Vector3_abs2(a)*Vector3_abs2(b) - ((a*b)*(a*b)+vector3_abs2(a^b)) << endl; cout << Vector3_abs2(a)*Vector3_abs2(b) << endl; } // main Αποτέλεσμα: (0, -1000, 0) 0 0 (0.1, 0.2, 0.3) (0.2, 0.3, 0.4) -0.1-3.27294e-018 0.0406 Οι τελευταίες δύο γραμμές χρειάζονται ένα σχόλιο. Η διαφορά που περιμένουμε μηδέν βγαίνει περίπου -3.3 10 18. Αλλά το γινόμενο a 2 b 2 έχει τιμή 0.0406 4 10 2. Όπως βλέπεις, κατ απόλυτη τιμή, η διαφορά είναι 10 16 φορές μικρότερη. Μπορούμε λοιπόν να τη θεωρήσουμε μηδέν (0).

492 Project 02