ΕΙΣΑΓΩΓΗ
Στο σημερινό δωρεάν μάθημα Java θα αναλύσουμε τα floating-point data types, τι πρέπει να προσέξουμε όταν κάνουμε αριθμητικές πράξεις με floating-point αριθμούς,
αλλά κυρίως πως μπορούμε εμείς
να ορίσουμε την σειρά εκτέλεσης των αριθμητικών πράξεων για να λάβουμε το σωστό
αποτέλεσμα.
FLOATING-POINT TYPES
Εκτός από
τους ακέραιους αριθμούς, μπορούμε να ορίσουμε μια Java μεταβλητή να δέχεται και δεκαδικούς
αριθμούς. Ο τρόπος να αναθέσουμε δεκαδικούς αριθμούς σε μια μεταβλητή είναι να
την ορίσουμε σαν float ή
σαν double. Η μόνη διαφορά ανάμεσα σε αυτά τα
δύο data types είναι το εύρος των αριθμών που μπορούν να καλύψουν αφού ένας float αριθμός περιγράφεται από 32
bits ενώ ένας double από 64 bits.
Στο
προηγούμενο δωρεάν μάθημα Java είχαμε αναφέρει ότι η default συμπεριφορά της Java με τους integral αριθμούς είναι να
προσπαθήσει να τους μετατρέψει όλους σε int
εκτός και αν βάλουμε το L στο τέλος του αριθμού και δηλώσουμε το data type να είναι long.
Στους floating-point αριθμούς η default συμπεριφορά είναι το double data type. Αν θέλουμε να ορίσουμε έναν αριθμό
να είναι float, εκτός
από τη δήλωση float data type μπροστά από το όνομα της μεταβλητής,
θα πρέπει να προσθέσουμε και ένα F στο
τέλος του αριθμού για να αναγνωριστεί σαν float.
Γενικότερα
το double data type είναι εκείνο που χρησιμοποιούμε
συχνότερα αφού έτσι και αλλιώς όλα τα μαθηματικά libraries της Java χρησιμοποιούν και επιστρέφουν double αριθμούς. Ας δούμε ένα απλό
παράδειγμα πριν προχωρήσουμε σε κάποια συγκεκριμένα σημεία όταν
προγραμματίζουμε με double μεταβλητές που πρέπει να προσέξουμε ιδιαίτερα.
App.java
Output
The sale price is 71.61
Το παραπάνω
πρόγραμμα το έχουμε ξαναδεί όταν είχαμε αναλύσει τα integral data types. Τώρα όμως, με την χρήση του double, κερδίζουμε σε ακρίβεια όσο αφορά τα
ψηφία μετά την υποδιαστολή, κάτι που δεν είχαμε με τους ακέραιους. Όπως θυμάστε
λοιπόν από την εξήγηση που δώσαμε στην προηγούμενη ενότητα, ο συγκεκριμένος
κώδικας ορίζει την αρχική τιμή ενός προϊόντος. Αφού υπολογίσουμε την έκπτωση,
την αφαιρούμε από την αρχική τιμή για δείχνουμε στο χρήστη την τελική τιμή του
προϊόντος.
Στο
συγκεκριμένο πρόγραμμα δεν έχει τίποτα το ιδιαίτερο να προσέξουμε γιατί οι
αριθμητικές πράξεις ήταν απλές. Ας δούμε τώρα ένα άλλο πρόγραμμα στο οποίο, αν
και πάλι η λογική είναι απλή, μπορεί να λάβετε λάθος αποτέλεσμα αν δεν
γνωρίζετε πως ακριβώς λειτουργεί η Java. Το συγκεκριμένο πρόγραμμα ορίζει τα
αποτελέσματα από τρία διαφορετικά τεστ και βρίσκει το μέσο όρο.
App.java
Output
The average score is 90.0
Το πρόγραμμα
μας λειτουργεί κανονικά χωρίς η Java να παραπονιέται για κάποιο συντακτικό σφάλμα, όμως το
αποτέλεσμα της διαίρεσης είναι λάθος. Το σωστό αποτέλεσμα είναι 90.666 και όχι
90.0. Τι έχει συμβεί εδώ? Για να καταλάβετε απόλυτα το πώς λάβαμε το
συγκεκριμένο λάθος αποτέλεσμα θα πρέπει να αναλύσουμε την γραμμή που υπολογίζει
το μέσο όρο βήμα-προς-βήμα.
Για να
βρούμε το μέσο όρο μιας ομάδα αριθμών, θα πρέπει πρώτα να τους προσθέσουμε. Σε
αυτό το σημείο του κώδικα κάνουμε ακριβώς αυτό – προσθέτουμε τα τρία
διαγωνίσματα. Τώρα η επόμενη ερώτηση σας θα είναι: γιατί ακριβώς χρειάζεται η
παρένθεση?
Στη Java, οι αριθμητικές πράξεις εκτελούνται
με σειρά προτεραιότητας. Multiplication ( * ), division ( / ) και remainder ( % ) εκτελούνται πρώτα. Εάν έχουμε
πολλαπλούς ίδιους arithmetic operators, για παράδειγμα multiplication και division τότε οι πράξεις εκτελούνται από τα αριστερά
στα δεξιά. Addition ( + ) και subtraction ( - ) operators εκτελούνται τελευταίοι. Ξανά, εάν έχουμε πολλαπλούς addition arithmetic operators και subtraction arithmetic operators στην ίδια δήλωση, τότε οι πράξεις εκτελούνται από τα αριστερά προς
τα δεξιά.
Αν τώρα
θέλουμε να επηρεάσουμε εμείς την σειρά εκτέλεσης των πράξεων και όχι να
αφήσουμε τον αυτόματο τρόπο της Java να αποφασίσει με βάση την προτεραιότητα των arithmetic operators, τότε πρέπει να βάλουμε μέσα σε
παρενθέσεις ( ( ) ) εκείνες τις πράξεις που θέλουμε να εκτελεστούν πρώτες. Οι παρενθέσεις
κατέχουν την κορυφή (έχουν την ανώτερη προτεραιότητα) ανάμεσα σε όλους τους arithmetic operators.
Γυρνώντας
λοιπόν πίσω στο απλό παράδειγμα μας, βλέπουμε ότι υπάρχει η εκτέλεση μιας
πρόσθεσης τριών μεταβλητών και μια διαίρεσης. Αν δεν τοποθετήσουμε τις τρεις
μεταβλητές μέσα σε παρένθεση, τότε η Java θα λειτουργήσει με την σειρά προτεραιότητας των συμβόλων και
θα πραγματοποιήσει την διαίρεση σαν πρώτο βήμα. Η διαίρεση, όπως φαντάζεστε θα
είναι λάθος γιατί θα διαιρεθεί ο αριθμός τρία μόνο με την τιμή 95 της μεταβλητής
test3. Μετά την
διαίρεση θα ακολουθήσει η πρόσθεση και των υπόλοιπων μεταβλητών. Οπότε έχοντας τις
τρεις μεταβλητές μέσα σε παρένθεση, επιβάλλουμε στη Java να εκτελέσει την πρόσθεση των
μεταβλητών σαν πρώτο βήμα και μετά την διαίρεση.
Σε αυτό το
σημείο η Java έχει
προσθέσει τις μεταβλητές και το αποτέλεσμα είναι o int αριθμός 272. Αυτός ο αριθμός
διαιρείται με τον int αριθμό
3. Η διαίρεση ανάμεσα σε δύο int αριθμούς δεν μπορεί να μας δώσει το ακριβές αποτέλεσμα. Οπότε
το αποτέλεσμα είναι ο int αριθμός 90.
Το
αποτέλεσμα της πρόσθεσης θα ανατεθεί σαν τιμή στην double μεταβλητή average. Όμως ένας int αριθμός (32-bits) είναι μικρότερος από έναν double (64-bits). Σε αυτό λοιπόν το σημείο η Java πραγματοποιεί αυτόματο casting μετατρέποντας τον int αριθμό 90 σε double αριθμό 90.0 για να συμφωνούν τα data types. Αφού γίνει το casting, πραγματοποιείται και και η ανάθεση του
αριθμού στη μεταβλητή average.
Τώρα που
καταλάβαμε τι ακριβώς συμβαίνει και γιατί πήραμε λάθος αποτέλεσμα, η επόμενη
ερώτηση είναι: πως μπορούμε να διορθώσουμε τον κώδικα μας?
Απάντηση
είναι εύκολη, γιατί γνωρίζοντας την θεωρία (που μόλις αναλύσαμε παραπάνω)
καταλάβαμε ότι πρέπει να επέμβουμε στον κώδικα πριν πραγματοποιηθεί η διαίρεση.
Εδώ θα μπορούσατε να προσφέρετε δύο πιθανές λύσεις.
Η πρώτη λύση
είναι να διαιρέσετε με τον double αριθμό 3.0 και όχι με τον int 3. Βλέποντας η Java ότι πρόκειται να εκτελέσει έναν int με έναν double αριθμό, αυτόματα θα μετατρέψει τον int σε double και μετά θα πραγματοποιήσει την
διαίρεση.
Χρησιμοποιώντας
την ίδια ακριβώς λογική, θα μπορούσαμε να κάνουμε casting σε double το αποτέλεσμα της πρόσθεσης. Πριν
πραγματοποιηθεί η διαίρεση η Java θα κάνει casting στον αριθμό 3 μετατρέποντας τον σε 3.0.
Ας επιλέξουμε
λοιπόν την δεύτερη προσέγγιση σαν λύση και σας την εφαρμόσουμε στον κώδικα μας για
να δούμε αν τώρα παίρνουμε το επιθυμητό αποτέλεσμα. Επίσης ας προσθέσουμε κα το
Double.MAX_VALUE όπως και το Double.ΜΙΝ_VALUE για να δούμε αντίστοιχα τον μεγαλύτερο και μικρότερο αριθμό
που μπορεί να φτάσει ένας double αριθμός.
App.java
Output
The average score is 90.66666666666667
The highest double value is 1.7976931348623157E308
The lowest double value is 4.9E-324
Πριν
κλείσουμε το σημερινό δωρεάν μάθημα Java, ας δούμε ένα από τα πιο γνωστά
παραδείγματα που αποδεικνύει την χρησιμότητα των floating-point μεταβλητών που δεν είναι άλλο από την
μετατροπή από Celcius βαθμούς
σε Fahrenheit.
App.java
Output
Celsius Temperature: 24
Fahrenheit Equivalent: 75.2
Όπως παρατηρήσατε
στη σημερινή ενότητα, η Java εκτελεί widening conversions αυτόματα γιατί νιώθει ασφάλεια ότι δεν
θα χάσει σε ακρίβεια το τελικό αποτέλεσμα. Ο παρακάτω πίνακας, ίσως σας βοηθήσει
έτσι ώστε να έχετε μια καλύτερη εικόνα κάτω από ποιες συνθήκες γίνεται αυτή η αυτόματη
μετατροπή.
Μην ξεχάσετε να κάνετε ένα μικρό donation έτσι ώστε αυτό το blog να μεγαλώσει ακόμα πιο πολύ και να έχει περισσότερες δυνατότητες στην online παράδοση δωρεάν μαθημάτων.
0 Comments
Η γνώμη σας είναι σημαντική.