DedSec Project

Ακέραιοι, κινητή υποδιαστολή και ακρίβεια — DedSec Project

Αριθμητική ακρίβεια — στρογγυλοποίηση με καθορισμένο κανόνα Κριτήρια επιτυχίας Ένα τοπικό εργαλείο πληρωμών δέχεται μη αρνητικά δεκαδικά ποσά ως κείμενο, με ένα έως τρία ψηφία μετά την…

Αριθμητική ακρίβεια — στρογγυλοποίηση με καθορισμένο κανόνα

Κριτήρια επιτυχίας

Ένα τοπικό εργαλείο πληρωμών δέχεται μη αρνητικά δεκαδικά ποσά ως κείμενο, με ένα έως τρία ψηφία μετά την υποδιαστολή. Το τελικό άθροισμα έχει δύο δεκαδικά ψηφία. Χρησιμοποίησε ROUND_HALF_EVEN και στρογγυλοποίησε μία φορά το τελικό σύνολο, όχι κάθε εγγραφή χωριστά. Τιμές NaN, Infinity, αρνητικά ποσά, εκθετική γραφή ή κενά πεδία απορρίπτονται. Πριν από την επεξεργασία χρηματικών ποσών, καθόρισε σαφώς τη μορφή εισόδου και τον τρόπο στρογγυλοποίησης.

Εκτελέσιμο εργαστήριο Python 3

Αποθήκευσε ως precision_lab.py και εκτέλεσε python3 precision_lab.py. Η βιβλιοθήκη decimal διατηρεί τα δεκαδικά ψηφία του αρχικού κειμένου, χωρίς ενδιάμεση προσέγγιση κινητής υποδιαστολής. Οι έλεγχοι συγκρίνουν τη στρογγυλοποίηση κάθε γραμμής με τη στρογγυλοποίηση του συνολικού ποσού.

from decimal import Decimal, InvalidOperation, ROUND_HALF_EVEN, ROUND_HALF_UP
import re
CENT = Decimal('0.01')
def rounded_total(values):
    total = Decimal(0)
    for token in values:
        if not isinstance(token, str) or not re.fullmatch(r'[0-9]+\.[0-9]{1,3}', token):
            raise ValueError('unsupported monetary input')
        total += Decimal(token)
    try:
        return total.quantize(CENT, rounding=ROUND_HALF_EVEN)
    except InvalidOperation as error:
        raise ValueError('amount outside active decimal precision') from error
assert rounded_total(['0.10', '0.20']) == Decimal('0.30')
assert rounded_total(['0.015'] * 3) == Decimal('0.04')
assert sum((Decimal('0.015').quantize(CENT, rounding=ROUND_HALF_EVEN) for _ in range(3)), Decimal(0)) == Decimal('0.06')
assert Decimal('1.005').quantize(CENT, rounding=ROUND_HALF_UP) == Decimal('1.01')
for bad in ('NaN', 'Infinity', '-2.00', '2e3', ''):
    try: rounded_total([bad])
    except ValueError: pass
    else: raise AssertionError('bad token accepted: ' + bad)
print('PASS precision: exact sum, rounding order, bad values')

Γιατί προκύπτουν διαφορετικά αποτελέσματα

Ένας δυαδικός float δεν μπορεί να αποθηκεύσει ακριβώς κάθε δεκαδικό κλάσμα. Στην Python το 0.1 + 0.2 δεν είναι ακριβώς ίσο με 0.3. Η Decimal από συμβολοσειρά διατηρεί την επιθυμητή δεκαδική τιμή, ενώ η Decimal από float μεταφέρει την προσέγγιση του float. Τρία ποσά 0.015 δίνουν 0.045: με ROUND_HALF_EVEN η τελική στρογγυλοποίηση παράγει 0.04. Αν πρώτα στρογγυλοποιηθεί κάθε ποσό σε 0.02, το άθροισμα γίνεται 0.06. Το ποιος κανόνας εφαρμόζεται εξαρτάται από τις πραγματικές λογιστικές απαιτήσεις. Για 1.005 η ROUND_HALF_UP δίνει 1.01, ενώ η HALF_EVEN δίνει 1.00.

Μικρές ασκήσεις και διάγνωση

  1. Σύγκρινε Decimal('0.1') και Decimal(0.1) και εξήγησε γιατί διαφέρουν.
  2. Δοκίμασε 0.00, 000.001, κενό πεδίο και άδεια λίστα. Κατάγραψε ποιες περιπτώσεις είναι αποδεκτές και τι επιστρέφουν.
  3. Αντικατάστησε προσωρινά τη HALF_EVEN με HALF_UP και βρες αριθμούς που επηρεάζονται. Η πολιτική δεν πρέπει να αλλάζει σιωπηλά.
  4. Προκάλεσε περιορισμό ακρίβειας με υπερβολικά μεγάλο δεκαδικό κείμενο και χειρίσου ρητά το σφάλμα.

Παραδοτέα: έξοδος PASS, πίνακας συγκρίσεων και τεκμηρίωση των πέντε απορριπτέων τιμών.

Πρόσθετη τεχνική ανάλυση

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

Πολιτικές δεκαδικής στρογγυλοποίησης και συμφωνία συνόλων