Στρογγυλοποίηση δεκαδικών και ακεραίων αριθμών στην Python με τα «round» και «Decimal.quantize».

Επιχείρηση

Τα παρακάτω εξηγούν πώς μπορείτε να στρογγυλοποιήσετε αριθμούς στην Python στρογγυλοποιώντας ή στρογγυλοποιώντας σε ζυγό αριθμό. Οι αριθμοί υποτίθεται ότι είναι τύπου float κινητής υποδιαστολής ή ακέραιου τύπου int.

  • ενσωματωμένη συνάρτηση (π.χ. σε γλώσσα προγραμματισμού): round()
    • Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων.
    • Στρογγυλοποίηση ακεραίων σε οποιονδήποτε αριθμό ψηφίων.
    • round() στρογγυλοποιεί σε ζυγό αριθμό, όχι σε κοινή στρογγυλοποίηση
  • τυποποιημένη βιβλιοθήκηdecimal quantize()
    • DecimalΔημιουργία ενός αντικειμένου
    • Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων και στρογγυλοποίηση σε ζυγούς αριθμούς
    • Στρογγυλοποίηση ακεραίων αριθμών σε οποιονδήποτε αριθμό ψηφίων και στρογγυλοποίηση σε ζυγούς αριθμούς
  • Ορίστε μια νέα συνάρτηση
    • Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων.
    • Στρογγυλοποίηση ακεραίων σε οποιονδήποτε αριθμό ψηφίων
    • Σημείωση: Για αρνητικές τιμές

Σημειώστε ότι, όπως αναφέρθηκε παραπάνω, η ενσωματωμένη συνάρτηση round δεν είναι μια γενική στρογγυλοποίηση, αλλά μια στρογγυλοποίηση σε ζυγό αριθμό. Βλέπε παρακάτω για λεπτομέρειες.

ενσωματωμένη συνάρτηση (π.χ. σε γλώσσα προγραμματισμού): round()

Η Round() παρέχεται ως ενσωματωμένη συνάρτηση. Μπορεί να χρησιμοποιηθεί χωρίς εισαγωγή οποιωνδήποτε ενοτήτων.

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

Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων.

Ακολουθεί παράδειγμα επεξεργασίας για τον τύπο float κινητής υποδιαστολής.

Εάν το δεύτερο όρισμα παραλείπεται, στρογγυλοποιείται σε ακέραιο αριθμό. Ο τύπος γίνεται επίσης ακέραιος τύπου int.

f = 123.456

print(round(f))
# 123

print(type(round(f)))
# <class 'int'>

Εάν καθοριστεί το δεύτερο όρισμα, επιστρέφει έναν τύπο float κινητής υποδιαστολής.

Εάν καθορίζεται θετικός ακέραιος αριθμός, καθορίζεται η δεκαδική θέση- εάν καθορίζεται αρνητικός ακέραιος αριθμός, καθορίζεται η ακέραια θέση. Το -1 στρογγυλοποιεί στο πλησιέστερο δέκατο, το -2 στρογγυλοποιεί στο πλησιέστερο εκατοστό και το 0 στρογγυλοποιεί σε ακέραιο (στην πρώτη θέση), αλλά επιστρέφει έναν τύπο float, σε αντίθεση με όταν παραλείπεται.

print(round(f, 1))
# 123.5

print(round(f, 2))
# 123.46

print(round(f, -1))
# 120.0

print(round(f, -2))
# 100.0

print(round(f, 0))
# 123.0

print(type(round(f, 0)))
# <class 'float'>

Στρογγυλοποίηση ακεραίων σε οποιονδήποτε αριθμό ψηφίων.

Ακολουθεί ένα παράδειγμα επεξεργασίας για τον ακέραιο τύπο int.

Εάν το δεύτερο όρισμα παραλειφθεί ή εάν καθοριστεί 0 ή ένας θετικός ακέραιος αριθμός, η αρχική τιμή επιστρέφεται ως έχει. Εάν καθοριστεί αρνητικός ακέραιος αριθμός, στρογγυλοποιείται στο αντίστοιχο ακέραιο ψηφίο. Και στις δύο περιπτώσεις, επιστρέφεται ένας ακέραιος τύπου int.

i = 99518

print(round(i))
# 99518

print(round(i, 2))
# 99518

print(round(i, -1))
# 99520

print(round(i, -2))
# 99500

print(round(i, -3))
# 100000

round() στρογγυλοποιεί σε ζυγό αριθμό, όχι σε κοινή στρογγυλοποίηση

Σημειώστε ότι η στρογγυλοποίηση με την ενσωματωμένη συνάρτηση round() στην Python 3 στρογγυλοποιεί σε ζυγό αριθμό και όχι σε γενική στρογγυλοποίηση.

Όπως αναφέρεται στην επίσημη τεκμηρίωση, το 0,5 στρογγυλοποιείται σε 0, το 5 στρογγυλοποιείται σε 0 κ.ο.κ.

print('0.4 =>', round(0.4))
print('0.5 =>', round(0.5))
print('0.6 =>', round(0.6))
# 0.4 => 0
# 0.5 => 0
# 0.6 => 1

print('4 =>', round(4, -1))
print('5 =>', round(5, -1))
print('6 =>', round(6, -1))
# 4 => 0
# 5 => 0
# 6 => 10

Ο ορισμός της στρογγυλοποίησης σε ζυγό αριθμό έχει ως εξής.

Αν το κλάσμα είναι μικρότερο από 0,5, στρογγυλοποιήστε το προς τα κάτω- αν το κλάσμα είναι μεγαλύτερο από 0,5, στρογγυλοποιήστε το προς τα πάνω- αν το κλάσμα είναι ακριβώς 0,5, στρογγυλοποιήστε το στον ζυγό αριθμό μεταξύ της στρογγυλοποίησης προς τα κάτω και της στρογγυλοποίησης προς τα πάνω.
Rounding – Wikipedia

Το 0,5 δεν είναι πάντα αποκομμένο.

print('0.5 =>', round(0.5))
print('1.5 =>', round(1.5))
print('2.5 =>', round(2.5))
print('3.5 =>', round(3.5))
print('4.5 =>', round(4.5))
# 0.5 => 0
# 1.5 => 2
# 2.5 => 2
# 3.5 => 4
# 4.5 => 4

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

print('0.05 =>', round(0.05, 1))
print('0.15 =>', round(0.15, 1))
print('0.25 =>', round(0.25, 1))
print('0.35 =>', round(0.35, 1))
print('0.45 =>', round(0.45, 1))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

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

Η συμπεριφορά της round() για αριθμούς κινητής υποδιαστολής μπορεί να σας εκπλήξει:Για παράδειγμα, η round(2.675, 2) θα σας δώσει 2.67 αντί για 2.68 όπως αναμενόταν. Αυτό δεν είναι σφάλμα.:Αυτό είναι αποτέλεσμα του γεγονότος ότι οι περισσότεροι δεκαδικοί αριθμοί δεν μπορούν να αναπαρασταθούν ακριβώς με αριθμούς κινητής υποδιαστολής.
round() — Built-in Functions — Python 3.10.2 Documentation

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

Σημειώστε επίσης ότι η round() στην Python 2 δεν είναι στρογγυλοποίηση σε ζυγό αριθμό, αλλά στρογγυλοποίηση.

quantize() της πρότυπης βιβλιοθήκης decimal

Η ενότητα decimal της τυπικής βιβλιοθήκης μπορεί να χρησιμοποιηθεί για τον χειρισμό ακριβών δεκαδικών αριθμών κινητής υποδιαστολής.

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

Οι καθορισμένες τιμές για το όρισμα στρογγυλοποίησης της μεθόδου quantize() έχουν τις ακόλουθες σημασίες, αντίστοιχα.

  • ROUND_HALF_UP:Γενική στρογγυλοποίηση
  • ROUND_HALF_EVEN:Στρογγυλοποίηση σε ζυγούς αριθμούς

Η ενότητα decimal είναι μια τυπική βιβλιοθήκη, οπότε δεν απαιτείται πρόσθετη εγκατάσταση, αλλά η εισαγωγή είναι απαραίτητη.

from decimal import Decimal, ROUND_HALF_UP, ROUND_HALF_EVEN

Δημιουργία ενός δεκαδικού αντικειμένου

Η Decimal() μπορεί να χρησιμοποιηθεί για τη δημιουργία αντικειμένων τύπου Decimal.

Αν καθορίσετε έναν τύπο float ως όρισμα, μπορείτε να δείτε ως τι αντιμετωπίζεται στην πραγματικότητα η τιμή.

print(Decimal(0.05))
# 0.05000000000000000277555756156289135105907917022705078125

print(type(Decimal(0.05)))
# <class 'decimal.Decimal'>

Όπως φαίνεται στο παράδειγμα, το 0,05 δεν αντιμετωπίζεται ως ακριβώς 0,05. Αυτός είναι ο λόγος για τον οποίο η ενσωματωμένη συνάρτηση round() που περιγράφεται παραπάνω στρογγυλοποιεί σε διαφορετική τιμή από την αναμενόμενη για δεκαδικές τιμές που περιλαμβάνουν το 0,05 στο παράδειγμα.

Δεδομένου ότι το 0,5 είναι το μισό (-1 δύναμη του 2), μπορεί να εκφραστεί ακριβώς με δυαδικό συμβολισμό.

print(Decimal(0.5))
# 0.5

Εάν καθορίσετε τον τύπο συμβολοσειράς str αντί του τύπου float, θα αντιμετωπιστεί ως ο δεκαδικός τύπος της ακριβούς τιμής.

print(Decimal('0.05'))
# 0.05

Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων και στρογγυλοποίηση σε ζυγούς αριθμούς

Καλέστε την quantize() από ένα αντικείμενο τύπου Decimal για να στρογγυλοποιήσετε την τιμή.

Το πρώτο όρισμα της quantize() είναι μια συμβολοσειρά με τον ίδιο αριθμό ψηφίων με τον αριθμό των ψηφίων που θέλετε να βρείτε, όπως '0.1' ή '0.01'.

Επιπλέον, το όρισμα ROUNDING προσδιορίζει τον τρόπο στρογγυλοποίησης- αν καθοριστεί ROUND_HALF_UP, χρησιμοποιείται γενική στρογγυλοποίηση.

f = 123.456

print(Decimal(str(f)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
# 123

print(Decimal(str(f)).quantize(Decimal('0.1'), rounding=ROUND_HALF_UP))
# 123.5

print(Decimal(str(f)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 123.46

Σε αντίθεση με την ενσωματωμένη συνάρτηση round(), το 0,5 στρογγυλοποιείται σε 1.

print('0.4 =>', Decimal(str(0.4)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
print('0.5 =>', Decimal(str(0.5)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
print('0.6 =>', Decimal(str(0.6)).quantize(Decimal('0'), rounding=ROUND_HALF_UP))
# 0.4 => 0
# 0.5 => 1
# 0.6 => 1

Εάν το όρισμα στρογγυλοποίηση έχει οριστεί σε ROUND_HALF_EVEN, η στρογγυλοποίηση πραγματοποιείται σε ζυγούς αριθμούς όπως στην ενσωματωμένη συνάρτηση round().

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

print('0.05 =>', round(0.05, 1))
print('0.15 =>', round(0.15, 1))
print('0.25 =>', round(0.25, 1))
print('0.35 =>', round(0.35, 1))
print('0.45 =>', round(0.45, 1))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

print('0.05 =>', Decimal(0.05).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.15 =>', Decimal(0.15).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.25 =>', Decimal(0.25).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.35 =>', Decimal(0.35).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.45 =>', Decimal(0.45).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
# 0.05 => 0.1
# 0.15 => 0.1
# 0.25 => 0.2
# 0.35 => 0.3
# 0.45 => 0.5

Εάν το όρισμα της Decimal() ορίζεται ως συμβολοσειρά τύπου str, αντιμετωπίζεται ως αντικείμενο Decimal με αυτήν ακριβώς την τιμή, οπότε το αποτέλεσμα είναι το αναμενόμενο.

print('0.05 =>', Decimal(str(0.05)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.15 =>', Decimal(str(0.15)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.25 =>', Decimal(str(0.25)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.35 =>', Decimal(str(0.35)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
print('0.45 =>', Decimal(str(0.45)).quantize(Decimal('0.1'), rounding=ROUND_HALF_EVEN))
# 0.05 => 0.0
# 0.15 => 0.2
# 0.25 => 0.2
# 0.35 => 0.4
# 0.45 => 0.4

Δεδομένου ότι το 0,5 μπορεί να αντιμετωπιστεί σωστά από τον τύπο float, δεν υπάρχει πρόβλημα στον προσδιορισμό του τύπου float ως όρισμα της Decimal() κατά τη στρογγυλοποίηση σε ακέραιο αριθμό, αλλά είναι ασφαλέστερο να προσδιορίσετε τον τύπο string str κατά τη στρογγυλοποίηση σε δεκαδικό ψηφίο.

Για παράδειγμα, το 2,675 είναι στην πραγματικότητα 2,67499…. σε τύπο float. Επομένως, αν θέλετε να στρογγυλοποιήσετε σε δύο δεκαδικά ψηφία, πρέπει να καθορίσετε μια συμβολοσειρά στην Decimal(), διαφορετικά το αποτέλεσμα θα διαφέρει από το αναμενόμενο αποτέλεσμα είτε στρογγυλοποιείτε στον πλησιέστερο ακέραιο αριθμό (ROUND_HALF_UP) είτε σε ζυγό αριθμό (ROUND_HALF_EVEN).

print(Decimal(2.675))
# 2.67499999999999982236431605997495353221893310546875

print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 2.67

print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_UP))
# 2.68

print(Decimal(2.675).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN))
# 2.67

print(Decimal(str(2.675)).quantize(Decimal('0.01'), rounding=ROUND_HALF_EVEN))
# 2.68

Σημειώστε ότι η μέθοδος quantize() επιστρέφει έναν αριθμό δεκαδικού τύπου, οπότε αν θέλετε να χειριστείτε έναν αριθμό τύπου float, πρέπει να τον μετατρέψετε σε τύπο float χρησιμοποιώντας την float(), διαφορετικά θα προκύψει σφάλμα.

d = Decimal('123.456').quantize(Decimal('0.01'), rounding=ROUND_HALF_UP)

print(d)
# 123.46

print(type(d))
# <class 'decimal.Decimal'>

# print(1.2 + d)
# TypeError: unsupported operand type(s) for +: 'float' and 'decimal.Decimal'

print(1.2 + float(d))
# 124.66

Στρογγυλοποίηση ακεραίων αριθμών σε οποιονδήποτε αριθμό ψηφίων και στρογγυλοποίηση σε ζυγούς αριθμούς

Αν θέλετε να στρογγυλοποιήσετε σε ένα ακέραιο ψηφίο, ο προσδιορισμός κάτι σαν '10' ως πρώτο όρισμα δεν θα σας δώσει το επιθυμητό αποτέλεσμα.

i = 99518

print(Decimal(i).quantize(Decimal('10'), rounding=ROUND_HALF_UP))
# 99518

Αυτό συμβαίνει επειδή η quantize() εκτελεί στρογγυλοποίηση σύμφωνα με τον εκθέτη του αντικειμένου Decimal, αλλά ο εκθέτης του Decimal('10') είναι 0 και όχι 1.

Μπορείτε να καθορίσετε έναν αυθαίρετο εκθέτη χρησιμοποιώντας το E ως συμβολοσειρά εκθέτη (π.χ. '1E1'). Ο εκθέτης εκθέτης μπορεί να ελεγχθεί στη μέθοδο as_tuple.

print(Decimal('10').as_tuple())
# DecimalTuple(sign=0, digits=(1, 0), exponent=0)

print(Decimal('1E1').as_tuple())
# DecimalTuple(sign=0, digits=(1,), exponent=1)

Ως έχει, το αποτέλεσμα θα είναι σε εκθετικό συμβολισμό χρησιμοποιώντας το E. Αν θέλετε να χρησιμοποιήσετε κανονικό συμβολισμό ή αν θέλετε να λειτουργήσετε με ακέραιο τύπο int μετά τη στρογγυλοποίηση, χρησιμοποιήστε την int() για να μετατρέψετε το αποτέλεσμα.

print(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP))
# 9.952E+4

print(int(Decimal(i).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 99520

print(int(Decimal(i).quantize(Decimal('1E2'), rounding=ROUND_HALF_UP)))
# 99500

print(int(Decimal(i).quantize(Decimal('1E3'), rounding=ROUND_HALF_UP)))
# 100000

Εάν το όρισμα στρογγυλοποίηση έχει οριστεί σε ROUND_HALF_UP, θα γίνει γενική στρογγυλοποίηση, π.χ. το 5 θα στρογγυλοποιηθεί σε 10.

print('4 =>', int(Decimal(4).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
print('5 =>', int(Decimal(5).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
print('6 =>', int(Decimal(6).quantize(Decimal('1E1'), rounding=ROUND_HALF_UP)))
# 4 => 0
# 5 => 10
# 6 => 10

Φυσικά, δεν υπάρχει πρόβλημα αν το καθορίσετε ως συμβολοσειρά.

Ορίστε μια νέα συνάρτηση

Η μέθοδος χρήσης της δεκαδικής μονάδας είναι ακριβής και ασφαλής, αλλά αν δεν αισθάνεστε άνετα με τη μετατροπή τύπου, μπορείτε να ορίσετε μια νέα συνάρτηση για να επιτύχετε γενική στρογγυλοποίηση.

Υπάρχουν πολλοί πιθανοί τρόποι για να το κάνετε αυτό, για παράδειγμα, η ακόλουθη συνάρτηση.

def my_round(val, digit=0):
    p = 10 ** digit
    return (val * p * 2 + 1) // 2 / p

Εάν δεν χρειάζεται να καθορίσετε τον αριθμό των ψηφίων και να στρογγυλοποιείτε πάντα στο πρώτο δεκαδικό ψηφίο, μπορείτε να χρησιμοποιήσετε μια απλούστερη μορφή.

my_round_int = lambda x: int((x * 2 + 1) // 2)

Εάν πρέπει να είστε ακριβείς, είναι ασφαλέστερο να χρησιμοποιείτε δεκαδικούς αριθμούς.

Τα παρακάτω είναι μόνο για αναφορά.

Στρογγυλοποίηση δεκαδικών ψηφίων σε οποιονδήποτε αριθμό ψηφίων.

print(int(my_round(f)))
# 123

print(my_round_int(f))
# 123

print(my_round(f, 1))
# 123.5

print(my_round(f, 2))
# 123.46

Σε αντίθεση με τη στρογγυλοποίηση, το 0,5 γίνεται 1 σύμφωνα με τη γενική στρογγυλοποίηση.

print(int(my_round(0.4)))
print(int(my_round(0.5)))
print(int(my_round(0.6)))
# 0
# 1
# 1

Στρογγυλοποίηση ακεραίων σε οποιονδήποτε αριθμό ψηφίων

i = 99518

print(int(my_round(i, -1)))
# 99520

print(int(my_round(i, -2)))
# 99500

print(int(my_round(i, -3)))
# 100000

Σε αντίθεση με τη στρογγυλοποίηση, το 5 γίνεται 10 σύμφωνα με την κοινή στρογγυλοποίηση.

print(int(my_round(4, -1)))
print(int(my_round(5, -1)))
print(int(my_round(6, -1)))
# 0
# 10
# 10

Σημείωση: Για αρνητικές τιμές

Στο παραπάνω παράδειγμα συνάρτησης, το -0,5 στρογγυλοποιείται στο 0.

print(int(my_round(-0.4)))
print(int(my_round(-0.5)))
print(int(my_round(-0.6)))
# 0
# 0
# -1

Υπάρχουν διάφοροι τρόποι σκέψης σχετικά με τη στρογγυλοποίηση για αρνητικές τιμές, αλλά αν θέλετε να μετατρέψετε το -0,5 σε -1, μπορείτε να το τροποποιήσετε ως εξής, για παράδειγμα

import math

def my_round2(val, digit=0):
    p = 10 ** digit
    s = math.copysign(1, val)
    return (s * val * p * 2 + 1) // 2 / p * s

print(int(my_round2(-0.4)))
print(int(my_round2(-0.5)))
print(int(my_round2(-0.6)))
# 0
# -1
# -1
Copied title and URL