Τεχνικό Άρθρο

Precision as displayed HotXLS: κανόνες rounding της Excel

Η Excel με precision as displayed στρογγυλοποιεί κάθε αποθηκευμένο αριθμό στα δεκαδικά που δείχνει το number format του: το section του format που ταιριάζει με το πρόσημο της τιμής, δύο επιπλέον δεκαδικά ανά %, τρία λιγότερα ανά κόμμα κλιμάκωσης χιλιάδων, με στρογγυλοποίηση μισού μακριά από το μηδέν. Το HotXLS εφαρμόζει τον ίδιο κανόνα και στις δύο engines του για Delphi όταν το TXLSXWorkbook.FullPrecision ή το TXLSWorkbook.UseFullPrecision είναι False. Ακούγεται σαν μονή γραμμή κώδικα μέχρι να αναφέρει πελάτης ότι τα σύνολα του τιμολογίου που εξάγετε διαφωνούν με την Excel κατά ένα cent, ή ότι στήλη διαρκείας σε [ss].00 κατέρρευσε στο μηδέν. Και τα δύο έγιναν, και τα δύο ανάγονται στο να πάει λάθος ένας από εκείνους τους κανόνες. Από το v2.384.57 οι δύο engines μοιράζονται μία ενιαία υλοποίηση της οποίας οι αναμενόμενες τιμές μετρήθηκαν στην Excel 16 με το Workbook.PrecisionAsDisplayed αναμμένο

Τι αλλάζει στην πραγματικότητα το precision as displayed σε ένα workbook;

Το precision as displayed είναι μία σημαία επιπέδου workbook που λέει στη calculation engine να αποθηκεύει τους αριθμούς όπως φαίνονται, όχι όπως υπολογίστηκαν. Στο UI της Excel κάθεται κάτω από File, Options, Advanced, «When calculating this workbook», ως «Set precision as displayed». Στον δίσκο είναι ένα bit. BIFF8 αρχείο το κουβαλά στην εγγραφή CalcPrecision ($000E, [MS-XLS] §2.4.35), της οποίας το πεδίο fFullPrec είναι 1 για κανονική πλήρη ακρίβεια και 0 όταν η επιλογή είναι αναμμένη. Ένα package XLSX το κουβαλά ως attribute fullPrecision του στοιχείου calcPr στο workbook.xml, ορισμένο στο ECMA-376 Part 1, όπου η προεπιλογή είναι true και το fullPrecision="0" ανάβει τη στρογγυλοποίηση

Η σημαία δεν είναι προτίμηση εμφάνισης. Όταν τσεκάρετε το κουτάκι, η Excel προειδοποιεί ότι τα δεδομένα θα χάσουν οριστικά ακρίβεια, και το εννοεί: οι τιμές ξαναγράφονται στην εμφανιζόμενη ακρίβειά τους, και τα ψηφία που κόπηκαν χάθηκαν. Το να ξετσεκάρετε το κουτάκι αργότερα δεν φέρνει πίσω τα παλιά ψηφία. Ένα 0.1234 που εμφανίζεται ως 12.3% γίνεται 0.123 για τα καλά

Το HotXLS διαβάζει και γράφει τη σημαία και στα δύο formats και την εκθέτει και στις δύο engines:

  • TXLSXWorkbook.FullPrecision: Boolean στην XLSX engine, φορτωμένο και αποθηκευμένο στο calcPr/@fullPrecision
  • TXLSWorkbook.UseFullPrecision: Boolean στην Classic engine (κι στο IXLSWorkbook), φορτωμένο και αποθηκευμένο στην εγγραφή CalcPrecision
  • Και τα δύο έχουν προεπιλογή True, που είναι η ασφαλής, καταστροφικά ανώδυνη λειτουργία και η προεπιλογή της Excel

Το πού εφαρμόζει τη στρογγυλοποίηση το HotXLS μετράει. Το HotXLS στρογγυλοποιεί στο σημείο όπου υπολογίζει τιμή: κάθε αποτέλεσμα τύπου στρογγυλοποιείται στην εμφανιζόμενη ακρίβειά του πριν αποθηκευτεί ως cached τιμή του κελιού, κατά το Recalculate και κατά την αποτίμηση κατά ζήτηση. Οι σταθερές που αναθέτετε μέσω Value αποθηκεύονται ακριβώς όπως δόθηκαν. Αν η έξοδός σας πρέπει να αναπαράγει όσα αποθηκεύει η Excel μετά το τσεκάρισμα του κουτακιού, στρογγυλοποιήστε εκείνες τις σταθερές μόνοι σας πριν τις γράψετε, για παράδειγμα με το helper που δείχνεται παρακάτω

Πώς αποφασίζει η Excel πόσα δεκαδικά θα κρατήσει;

Η Excel παράγει το πλήθος των δεκαδικών που κρατούνται από το συγκεκριμένο section του format που εμφανίζει την τιμή, όχι από το format string ως σύνολο. Οι κανόνες παρακάτω μετρήθηκαν στην Excel 16 και είναι όσα υλοποιεί το XlsApplyDisplayedPrecision στο lxNumFormat και για τις δύο engines του HotXLS

  1. Διάλεξε section από το πρόσημο. Ένα format δύο sections χρησιμοποιεί το δεύτερο section για αρνητικές τιμές. Ένα format με τρία ή περισσότερα sections χρησιμοποιεί το δεύτερο για αρνητικές τιμές και το τρίτο για ακριβώς μηδέν. Όλα τα άλλα χρησιμοποιούν το πρώτο section
  2. Μετρήσε τους placeholders δεκαδικών. Κάθε 0, # ή ? μετά από την υποδιαστολή σε εκείνο το section προσθέτει ένα κρατούμενο δεκαδικό
  3. Πρόσθεσε δύο ανά σύμβολο %. Το 0.0% δείχνει το 0.1234 ως 12.3%, οπότε η αποθηκευμένη τιμή είναι το εκατοστό του ό,τι βλέπετε και κρατά τρία δεκαδικά, όχι ένα
  4. Αφαίρεσε τρία ανά κόμμα κλιμάκωσης. Κόμμα μετά από τον τελευταίο placeholder ακεραίου (0,, 0.0,, 0,.0) διαιρεί την εμφάνιση με 1000. Το 0.0, δείχνει το 12345.678 ως 12.3, οπότε η Excel κρατά ένα δεκαδικό μείον τρία, που είναι αρνητικό πλήθος: η τιμή στρογγυλοποιείται στις εκατοντάδες και αποθηκεύεται ως 12300. Κόμμα ανάμεσα σε placeholders ακεραίων, όπως στο #,##0, είναι σκέτη ομαδοποίηση ψηφίων και δεν αλλάζει τίποτα
  5. Άσε ήσυχα τα μη αριθμητικά sections. Sections General, ημερομηνίας και ώρας (συμπεριλαμβανομένων των elapsed [h], [mm] και [ss]), scientific, fraction και text sections, και sections χωρίς κανένα placeholder ψηφίου κρατούν πλήρη ακρίβεια
Διάγραμμα HotXLS των κανόνων εμφανιζόμενης ακρίβειας: διάλεξε το section του format από το πρόσημο της τιμής, μέτρα τα placeholders ψηφίων μετά από την υποδιαστολή, πρόσθεσε δύο δεκαδικά ανά σύμβολο %, αφαίρεσε τρία ανά κόμμα κλιμάκωσης χιλιάδων ώστε το πλήθος μπορεί να πάει αρνητικό, προσπέρνα τελείως sections General και ημερομηνίας-ώρας, μετά στρογγυλοποίησε μισό μακριά από το μηδέν
Το πλήθος ψηφίων βγαίνει από το section που ταιριάζει με το πρόσημο, συν δύο ανά % και μείον τρία ανά κόμμα κλιμάκωσης, και αρνητικό πλήθος στρογγυλοποιεί σε δεκάδες ή εκατοντάδες· sections General και ημερομηνίας μένουν ήσυχα

Μετρημένοι απέναντι στην Excel 16, αυτοί είναι οι τιμές που αποθηκεύουν πλέον και οι δύο engines του HotXLS για αποτέλεσμα τύπου σε κάθε format:

Number formatΥπολογιζόμενη τιμήΑποθηκευμένη τιμήΚανόνας που ισχύει
0.0%0.12340.123Ένα δεκαδικό συν δύο για το σύμβολο %
02.53Μισό μακριά από το μηδέν, όχι προς το άρτιο
0-2.5-3Μισό μακριά από το μηδέν και στην αρνητική πλευρά
0.00;(0.0)-1.2345-1.2Το αρνητικό section δείχνει ένα δεκαδικό
0.00;(0.0)1.23451.23Το θετικό section δείχνει δύο δεκαδικά
#,##0.01234.56781234.6Κόμμα ομαδοποίησης, χωρίς κλιμάκωση
0.0,12345.67812300Ένα δεκαδικό μείον τρία: στρογγυλοποίηση σε εκατοντάδες
0.0%;(0.00%)-0.0125-0.0125Το αρνητικό section κρατά δύο συν δύο δεκαδικά
0.001.0051.01Ανοχή για σφάλμα δυαδικής αναπαράστασης
0;-0;0.00.51Όχι μηδέν, οπότε αποφασίζει το θετικό section

Η τελευταία σειρά είναι ωραία παγίδα. Η τιμή 0.5 στρογγυλοποιείται σε ακέραιο, και το section μηδέν δεν μπαίνει ποτέ στη μέση, επειδή η Excel διαλέγει section από την υπολογισμένη τιμή πριν τη στρογγυλοποίηση. Μία τίμια limitation από την πλευρά του HotXLS: τα sections διαλέγονται μόνο από το πρόσημο, οπότε format των οποίων τα sections κουβαλάνε προσαρμοσμένες συνθήκες αγκυλών όπως [>=1000] εξακολουθεί να χωρίζεται κατά πρόσημο. Τσεκάρετε τέτοια formats απέναντι στην Excel αν σας μετράει

Γιατί το 1.005 στρογγυλοποιείται σε 1.01 και όχι σε 1.00;

Η Excel στρογγυλοποιεί το 1.005 σε κελί 0.00 σε 1.01 παρόλο που το double πιο κοντά στο 1.005 είναι λίγο κάτω από το μισό δρόμο, και το HotXLS το ταιριάζει με ανοχή λίγων ulp. Το literal 1.005 δεν αναπαρίσταται σε δυαδική κινητή υποδιαστολή. Το πιο κοντινό double IEEE 754 είναι το 1.00499999999999989341858963598497211933135986328125, και ο πολλαπλασιασμός με 100 δίνει 100.49999999999999. Ένα βιβλιακό Floor(x * 100 + 0.5) / 100 επιστρέφει άρα 1.00, που διαφωνεί με τον αριθμό που πληκτρολόγησε ο χρήστης, με όσα δείχνει η Excel, και με όσα αποθηκεύει η Excel

Το Delphi προσθέτει τη δική του πινελιά. Το System.Round στρογγυλοποιεί ισοπαλίες προς το άρτιο, οπότε το Round(2.5) είναι 2 και το Round(3.5) είναι 4. Αυτό είναι banker’s rounding, λογική προεπιλογή για στατιστική και λάθος κανόνας εδώ: η Excel αποθηκεύει 3 για 2.5 σε κελί 0 και -3 για -2.5. Η υλοποίηση του HotXLS δουλεύει πάνω στην απόλυτη τιμή, προσθέτει 0.5 συν σχετική ανοχή 2-51 επί την κλιμακωμένη τιμή (λίγα ulp σε εκείνο το μέγεθος, ποτέ λιγότερα από δύο ulp του 1.0), κόβει, ξε-κλιμακώνει και επαναφέρει το πρόσημο. Η παρακάτω συνάρτηση είναι αυτοτελής επεξήγηση εκείνης της αρχής, όχι ο ίδιος ο κώδικας της βιβλιοθήκης, και χειρίζεται αρνητικά πλήθη ψηφίων για κόμματα κλιμάκωσης με τον ίδιο τρόπο:

Διάγραμμα στρογγυλοποίησης HotXLS: το 2.5 στρογγυλοποιείται μισό μακριά από το μηδέν σε 3 και το -2.5 σε -3, εκεί που το Delphi System.Round δίνει τις banker απαντήσεις 2 και -2, και αφού το πιο κοντινό double στο 1.005 κάθεται λίγο κάτω από το μισό δρόμο, η ανοχή λίγων ulp είναι αυτή που μετατρέπει ένα floor-based 1.00 στην απάντηση της Excel 1.01
Η Excel στρογγυλοποιεί ισοπαλίες μακριά από το μηδέν και συγχωρεί σφάλμα δυαδικής αναπαράστασης με μικρή ανοχή· και οι δύο λεπτομέρειες μετρούνται, και το να παραλείψεις όποια από τις δύο αποθηκεύει 2 για 2.5 ή 1.00 για 1.005, ένα cent μακριά από την Excel
// Σκίτσο αρχής: στρογγυλοποίησε μισό μακριά από το μηδέν σε ADigits δεκαδικά,
// με ανοχή λίγων ulp ώστε το 1.005 να φτάσει το 1.01.
// ADigits < 0 στρογγυλοποιεί σε δεκάδες, εκατοντάδες, ... (το "0.0," δίνει -2)
function RoundAsDisplayed(AValue: Double; ADigits: Integer): Double;
const
  Tolerance = 4.440892098500626E-16; // 2^-51, δύο ulp του 1.0
var
  I: Integer;
  Scale, Scaled, Eps: Double;
begin
  Result := AValue;
  if (ADigits < -15) or (ADigits > 14) then
    Exit; // πέρα από ακρίβεια double: άσε την τιμή ήσυχη
  Scale := 1;
  for I := 1 to Abs(ADigits) do
    Scale := Scale * 10;
  if ADigits >= 0 then
  begin
    if Abs(AValue) > 1E300 / Scale then
      Exit; // η κλιμάκωση θα έκανε overflow
    Scaled := Abs(AValue) * Scale;
  end
  else
    Scaled := Abs(AValue) / Scale;
  Eps := Scaled * Tolerance;
  if Eps < Tolerance then
    Eps := Tolerance;
  Scaled := Int(Scaled + 0.5 + Eps); // μισό μακριά από το μηδέν, όχι Round()
  if ADigits >= 0 then
    Result := Scaled / Scale
  else
    Result := Scaled * Scale;
  if AValue < 0 then
    Result := -Result;
end;

// RoundAsDisplayed(1.005, 2)      = 1.01   (με Floor: 1.00)
// RoundAsDisplayed(2.5, 0)        = 3      (με Round: 2)
// RoundAsDisplayed(-2.5, 0)       = -3
// RoundAsDisplayed(0.1234, 3)     = 0.123  ("0.0%": 1 + 2 digits)
// RoundAsDisplayed(12345.678, -2) = 12300  ("0.0,": 1 - 3 digits)

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

Τι πήγε στραβά πριν το v2.384.57;

Πριν το v2.384.57 η XLSX engine και η Classic engine είχαν η καθεμιά τον δικό της κώδικα precision-as-displayed, και η καθεμία ήταν λάθος με διαφορετικό τρόπο. Αν παράγετε workbooks με την επιλογή αναμμένη, αυτά είναι τα συμπτώματα προς αναζήτηση σε αρχεία από παλαιότερα builds

XLSX engine: μόνο πρώτο section, χωρίς %, banker’s rounding

Η παλιά διαδρομή XLSX ζητούσε το πλήθος δεκαδικών του format string ως συνόλου, που κοίταζε μόνο το πρώτο section και αγνοούσε το %, και μετά στρογγυλοποιούσε με Round. Ένα 0.1234 σε 0.0% αποθηκευόταν ως 0.1, δηλαδή 10% αντί για το 12.3% στην οθόνη. Ένα 2.5 σε 0 αποθηκευόταν ως 2 αντί για 3. Αρνητικές τιμές σε format όπως 0.00;(0.0) στρογγυλοποιούνταν στα δύο δεκαδικά του θετικού section. Από το v2.384.57 η XLSX engine καλεί την ίδια μοιρασμένη ρουτίνα με την Classic engine, που επίσης απέκτησε υποστήριξη κόμματος κλιμάκωσης σε εκείνο το release

Classic engine: το TRUE έγινε -1

Η Classic engine προστάτευε τη στρογγυλοποίησή της με VarIsNumeric, και το VarIsNumeric επιστρέφει True για Variant varBoolean. Η μετατροπή εκείνου του Variant με Double(V) δίνει -1, επειδή Boolean True τύπου COM αποθηκεύεται ως -1. Τύπος όπως =A1>0 σε κελί με format 0.00 έβγαινε άρα από τον επανυπολογισμό ως ο αριθμός -1. Από το v2.384.57 Boolean αποτελέσματα αποκλείονται πριν από κάθε αριθμητικό έλεγχο, και λογικό αποτέλεσμα μένει λογικό αποτέλεσμα και στις δύο engines

Formats elapsed-time διαβάζονταν ως χρώματα (v2.384.9)

Το τρίτο bug καθόταν στο μοντέλο number-format και όχι στη στρογγυλοποίηση. Ο parser ταξινομούσε κάθε bracketed token που δεν ήταν συνθήκη ως χρώμα, οπότε τα [h], [mm] και [ss] δεν σήμαναν ποτέ το section τους ως date/time. Η εμφάνιση δεν επηρεαζόταν, επειδή το formatting τρέχει σε ξεχωριστή διαδρομή, αλλά το precision as displayed βασίζεται σε εκείνη τη σημαία για να προσπερνά τιμές χρόνου. Μια διάρκεια πέντε δευτερολέπτων είναι 5/86400 της ημέρας, περίπου 0.0000579, και ένα format όπως [ss].00 έμοιαζε με συνηθισμένο αριθμό δύο δεκαδικών, οπότε με FullPrecision κλειστή η διάρκεια στρογγυλοποιούνταν σε 0.00 ημέρες. Από το v2.384.9 ένα bracketed run ενός μόνο γράμματος h, m ή s γίνεται parse ως token elapsed-time και το section μεταχειρίζεται ως date/time. Το ίδιο release διόρθωσε την ανίχνευση λεπτών στο h:mm, όπου η άνω-κάτω τελεία ανάμεσα στα tokens έκρυβε την ώρα από τον parser

Διάγραμμα HotXLS λάθος parse elapsed time: πέντε δευτερόλεπτα αποθηκευμένα ως μικροσκοπικό κλάσμα ημέρας σε κελί με format του bracketed token ss, που ο παλιός parser διάβαζε ως χρώμα και σημαίαρε ως σκέτο αριθμό δύο δεκαδικών, οπότε το precision as displayed στρογγυλοποιούσε τη διάρκεια σε 0.00 έως ότου γίνει parse ως section elapsed time
Το formatting έτρεχε σε δική του διαδρομή, οπότε το κελί φαινόταν σωστό ενώ η αποθηκευμένη τιμή στρογγυλοποιούνταν στο μηδέν· bracketed μονό γράμμα h, m ή s είναι token elapsed time, όχι χρώμα, και το section κρατά πλήρη ακρίβεια

Ενεργοποίηση precision as displayed στο HotXLS από Delphi

Για να πάρετε αποθηκευμένες τιμές ισοδύναμες της Excel, ορίστε τη σημαία πριν τον επανυπολογισμό που πρέπει να την τιμήσει, μετά διαβάστε τα cached αποτελέσματα ή σώστε. Στην XLSX engine το FullPrecision είναι σκέτη σημαία: η αλλαγή της δεν ακυρώνει αποτελέσματα που ήδη αποθήκευσε προηγούμενο Recalculate, οπότε ορίστε τη αμέσως μετά Create ή Open και πριν το πρώτο Recalculate. Το παράδειγμα χρησιμοποιεί τύπους επειδή εκεί εφαρμόζει τη στρογγυλοποίηση το HotXLS:

var
  Wb: TXLSXWorkbook;
  Sh: TXLSXWorksheet;
begin
  Wb := TXLSXWorkbook.Create;
  try
    Sh := Wb.Sheets.Add('Totals');
    Sh.Cells[1, 1].Value := 0.1234;
    Sh.Cells[2, 1].Value := 2.5;
    Sh.Cells[3, 1].Value := 12345.678;

    Sh.Cells[1, 2].Formula := '=A1';
    Sh.Cells[1, 2].NumberFormat := '0.0%';   // δείχνει 12.3%
    Sh.Cells[2, 2].Formula := '=A2';
    Sh.Cells[2, 2].NumberFormat := '0';      // δείχνει 3
    Sh.Cells[3, 2].Formula := '=A3';
    Sh.Cells[3, 2].NumberFormat := '0.0,';   // δείχνει 12.3 (χιλιάδες)

    // Πρέπει να οριστεί πριν το πρώτο Recalculate στην XLSX engine
    Wb.FullPrecision := False;
    Wb.Recalculate;

    // Τα cached αποτελέσματα τώρα ταιριάζουν Excel 16: 0.123, 3 και 12300.
    // Οι σταθερές στη στήλη A κρατούν την πλήρη ακρίβειά τους.
    Assert(Abs(Double(Sh.Cells[1, 2].Value) - 0.123) < 1E-12);
    Assert(Double(Sh.Cells[2, 2].Value) = 3);
    Assert(Double(Sh.Cells[3, 2].Value) = 12300);

    Wb.SaveAs('totals.xlsx'); // γράφει <calcPr fullPrecision="0"/>
  finally
    Wb.Free;
  end;
end;

Η Classic engine συμπεριφέρεται το ίδιο, με μία ευκολία: η ανάθεση στο TXLSWorkbook.UseFullPrecision σημαίνει dirty κάθε τύπο στο dependency graph, οπότε το επόμενο Recalculate ξανα-αποτιμά όλο το workbook υπό τον νέο κανόνα. Η αλλαγή NumberFormat ενώ η επιλογή είναι αναμμένη σημαίνει επίσης dirty τα επηρεαζόμενα κελιά τύπων, επειδή το format τώρα αποφασίζει την αποθηκευμένη τιμή. Σημειώστε ότι το Classic Recalculate επιστρέφει το πλήθος των κελιών τύπων που δεν μπόρεσε να αποτιμήσει, οπότε το μηδέν σημαίνει επιτυχία:

var
  Wb: TXLSWorkbook;
  Sh: TXLSWorksheet;
begin
  Wb := TXLSWorkbook.Create;
  try
    Sh := Wb.Sheets.Add;
    Sh.Range['A1', 'A1'].Value := -1.2345;
    Sh.Range['B1', 'B1'].Formula := '=A1';
    Sh.Range['B1', 'B1'].NumberFormat := '0.00;(0.0)';
    Sh.Range['C1', 'C1'].Formula := '=A1<0';
    Sh.Range['C1', 'C1'].NumberFormat := '0.00';

    Wb.UseFullPrecision := False; // σημαίνει dirty κάθε τύπο
    if Wb.Recalculate <> 0 then
      raise Exception.Create('Some formulas could not be evaluated');

    // B1 = -1.2: το αρνητικό section "(0.0)" δείχνει ένα δεκαδικό
    // C1 μένει Boolean True (builds πριν το v2.384.57 αποθήκευαν -1)
    Wb.SaveAs('report.xls'); // εγγραφή CalcPrecision με fFullPrec = 0
  finally
    Wb.Free;
  end;
end;

Και οι δύο engines τιμούν επίσης τη σημαία που έρχεται μέσα με αρχείο. Ανοίξτε workbook αποθηκευμένο με την επιλογή αναμμένη και το FullPrecision ή UseFullPrecision είναι ήδη False, οπότε Recalculate μετά τη φόρτωση στρογγυλοποιεί ακριβώς όπως θα έκανε η Excel. Αν χρειάζεστε μόνο να διαβάσετε τους αριθμούς που αποθήκευσε ήδη η Excel, μπορείτε να προσπεράσετε τελείως τον επανυπολογισμό, όπως περιγράφεται στο διάβασμα cached τιμών τύπων χωρίς επανυπολογισμό. Για το πώς αλληλεπιδρούν serial αριθμοί ημερομηνιών και formats ημερομηνίας με το μοντέλο format που κινεί τον έλεγχο date/time, δείτε Excel date serials, το σύστημα 1904 και numFmt στο Delphi

Πότε ανάβεις το precision as displayed και πότε όχι;

Ανάψτε precision as displayed μόνο όταν οι αποθηκευμένοι αριθμοί του workbook πρέπει να ισούνται με τους εμφανιζόμενους, και δέχεστε να χάσετε τα επιπλέον ψηφία για πάντα. Η κλασική νόμιμη περίπτωση είναι οικονομικό πρόγραμμα όπου στήλες στρογγυλεμένων ποσών πρέπει να αθροίζονται στο στρογγυλεμένο σύνολο στην οθόνη, χωρίς κρυφά κλάσματα cent να παράγουν σύνολο που αστοχεί κατά ένα στην τελευταία θέση. Το να ταιριάξετε υπάρχον workbook πελάτη που έχει ήδη την επιλογή ορισμένη είναι ο άλλος καλός λόγος, και το HotXLS διατηρεί τη σημαία στο round-trip ώστε να μην τις γυρνάτε σιωπηλά σε πλήρη ακρίβεια

Αποφύγετέ το στις περισσότερες άλλες καταστάσεις:

  • Δεδομένα μηχανικής και επιστήμης. Το να στρογγυλοποιήσεις μια μέτρηση επειδή κάποιος διάλεξε format δύο δεκαδικών για report καταστρέφει πληροφορία που καμία μεταγενέστερη αλλαγή format δεν μπορεί να επαναφέρει
  • Ποσοστά με χοντρικά formats. Ένα format 0% κρατά μόνο δύο δεκαδικά της αποθηκευμένης αναλογίας, οπότε το 0.1234 γίνεται 0.12, και κάθε κατάντη τύπος που διαβάζει το κελί δουλεύει με 0.12
  • Κλιμακωμένες εμφανίσεις. Ένα format 0, ή 0.0, που χρησιμοποιείται για να δείχνει χιλιάδες στρογγυλοποιεί την αποθηκευμένη τιμή στις χιλιάδες ή εκατοντάδες, που σπάνια είναι ό,τι ήθελε ο άνθρωπος που διάλεξε το format
  • Μοιρασμένα templates. Η σημαία είναι σε επίπεδο workbook. Όποιος προσθέσει αργότερα sheet κληρονομεί τη συμπεριφορά, συνήθως χωρίς να ξέρει ότι είναι αναμμένη

Αν αυτό που πραγματικά θέλετε είναι στρογγυλεμένα αποτελέσματα σε λίγα συγκεκριμένα κελιά, γράψτε ROUND σε εκείνους τους τύπους αντί αυτού. Το ROUND είναι ρητό, τοπικό στο κελί, ορατό σε όποιον διαβάζει τον τύπο, και αποτιμάται από τη formula engine του HotXLS σαν κάθε άλλη συνάρτηση, χωρίς workbook-wide παρενέργειες

Σύντομη αναφορά precision as displayed

  • Σημαία αρχείου: CalcPrecision $000E με fFullPrec = 0 σε BIFF8 ([MS-XLS] §2.4.35), calcPr fullPrecision="0" σε XLSX (ECMA-376 Part 1)
  • Διακόπτες HotXLS: TXLSXWorkbook.FullPrecision := False και TXLSWorkbook.UseFullPrecision := False, και οι δύο προεπιλογή True
  • Section: διαλέγεται από το πρόσημο της υπολογισμένης τιμής· τρίτο section μόνο για ακριβώς μηδέν
  • Ψηφία: placeholders δεκαδικών, συν δύο ανά %, μείον τρία ανά κόμμα κλιμάκωσης· το πλήθος μπορεί να είναι αρνητικό
  • Στρογγυλοποίηση: μισό μακριά από το μηδέν με ανοχή λίγων ulp, οπότε 2.5 δίνει 3, -2.5 δίνει -3 και 1.005 δίνει 1.01
  • Προπερνιούνται: General, date/time και elapsed time, scientific, fraction, text, τιμές Boolean και σφάλματος
  • Εμβέλεια στο HotXLS: αποτελέσματα τύπων καθώς υπολογίζονται· οι σταθερές αποθηκεύονται όπως ανατέθηκαν
  • XLSX engine: ορίστε FullPrecision πριν το πρώτο Recalculate· ο Classic setter ξανασημαίνει dirty όλους τους τύπους μόνος του
  • Εκδόσεις: συμφωνεί με Excel 16 και στις δύο engines από το v2.384.57· formats elapsed-time προστατευμένα από το v2.384.9

Το HotXLS διαβάζει, γράφει και υπολογίζει workbooks XLS και XLSX εγγενώς από Delphi και C++Builder, συμπεριλαμβανομένων των επιλογών υπολογισμού workbook που καλύφθηκαν εδώ. Λεπτομέρειες, εκδόσεις και δοκιμαστική λήψη στη σελίδα HotXLS Delphi spreadsheet component