מאמר טכני

Precision as Displayed ב-HotXLS: כללי העיגול של Excel

precision as displayed של Excel מעגל כל מספר שנשמר אל הספרות העשרוניות שפורמט המספר שלו מציג: המקטע של הפורמט שתואם את הסימן של הערך, שתי ספרות נוספות לכל %, שלוש פחות לכל פסיק של קניית מידה לאלפים, עיגול חצי בכיוון הרחוק מהאפס. HotXLS מיישם את הכלל הזה בשני המנועים שלו ל-Delphi כש-TXLSXWorkbook.FullPrecision או TXLSWorkbook.UseFullPrecision הוא False. זה נשמע כמו שורה אחת עד שלקוח מדווח שסכומי החשבונית שייצאתם חורגים מ-Excel בסנט אחד, או שעמודה של משכי זמן ב-[ss].00 התמוטטה לאפס. שניהם קרו, ושניהם חזרו לטעות אחת מהכללים האלה. מאז v2.384.57 שני המנועים חולקים מימוש אחד שהערכים הצפויים שלו נמדדו ב-Excel 16 עם Workbook.PrecisionAsDisplayed מופעל

מה precision as displayed באמת משנה בחוברת עבודה?

precision as displayed הוא דגל בודד ברמת חוברת העבודה שאומר למנוע החישוב לשמור מספרים כפי שהם נראים, לא כפי שחושבו. ב-UI של Excel הוא יושב תחת File, Options, Advanced, "When calculating this workbook", בשם "Set precision as displayed". על הדיסק זה ביט אחד. קובץ BIFF8 נושא אותו ברשומת CalcPrecision ($000E, [MS-XLS] §2.4.35), שהשדה fFullPrec שלה הוא 1 עבור דיוק מלא רגיל ו-0 כשהאפשרות דלוקה. חבילת XLSX נושאת אותו בתור התכונה fullPrecision של האלמנט calcPr ב-workbook.xml, שהוגדר ב-ECMA-376 חלק 1, שם ברירת המחדל היא true ו-fullPrecision="0" מדליק את העיגול

הדגל אינו העדפת תצוגה. כשמסמנים את התיבה, Excel מזהיר שהנתונים יאבדו דיוק לצמיתות, והוא מתכוון לזה: הערכים נכתבים מחדש בדיוק המוצג שלהם, והספרות שנחתכו נעלמו. ניקוי התיבה אחר כך לא מחזיר את הספרות הישנות. 0.1234 שמוצג בתור 12.3% נהיה 0.123 לתמיד

HotXLS קורא וכותב את הדגל בשני הפורמטים וחושף אותו בשני המנועים:

  • TXLSXWorkbook.FullPrecision: Boolean במנוע ה-XLSX, נטען ונשמר אל calcPr/@fullPrecision
  • TXLSWorkbook.UseFullPrecision: Boolean במנוע הקלאסי (גם על IXLSWorkbook), נטען ונשמר אל רשומת ה-CalcPrecision
  • שניהם כברירת מחדל True, שהוא המצב הבטוח שאינו הרסני וברירת המחדל של Excel

היכן ש-HotXLS מיישם את העיגול חשוב. HotXLS מעגל בנקודה שבה הוא מחשב ערך: כל תוצאת נוסחה מעוגלת לדיוק המוצג שלה לפני שהיא נשמרת בתור הערך המטמוני של התא, במהלך Recalculate ובמהלך חישוב על דרישה. קבועים שמשויכים דרך Value נשמרים בדיוק כפי שניתנו. אם הפלט שלכם צריך לשחזר את מה ש-Excel שומר אחרי שהתיבה מסומנת, עגלו את הקבועים האלה בעצמכם לפני הכתיבה, למשל עם העוזר שמוצג בהמשך

איך Excel מחליט כמה ספרות עשרוניות לשמור?

Excel גוזר את מספר הספרות העשרוניות שנשמרות ממקטע הפורמט הספציפי שמציג את הערך, ולא ממחרוזת הפורמט כולה. הכללים להלן נמדדו ב-Excel 16 והם מה ש-XlsApplyDisplayedPrecision ב-lxNumFormat מממש עבור שני מנועי HotXLS

  1. בוחרים מקטע לפי סימן. פורמט בן שני מקטעים משתמש במקטע השני עבור ערכים שליליים. פורמט עם שלושה מקטעים ומעלה משתמש בשני עבור ערכים שליליים ובשלישי עבור אפס בדיוק. כל השאר משתמש במקטע הראשון
  2. סופרים ממלאי מקום עשרוניים. כל 0, # או ? אחרי הנקודה העשרונית באותו מקטע מוסיף ספרה עשרונית שנשמרת
  3. מוסיפים שתיים לכל סימן אחוז. 0.0% מציג את 0.1234 בתור 12.3%, ולכן הערך השמור הוא מאית ממה שרואים ומחזיק שלוש ספרות עשרוניות, לא אחת
  4. מחסירים שלוש לכל פסיק קניית מידה. פסיק אחרי ממלא המקום השלם האחרון (0,, 0.0,, 0,.0) מחלק את התצוגה ב-1000. 0.0, מציג את 12345.678 בתור 12.3, ולכן Excel שומר ספרה עשרונית אחת פחות שלוש, מה שהוא ספירה שלילית: הערך מעוגל אל המאות ונשמר בתור 12300. פסיק בין ממלאי מקום שלמים, כמו ב-#,##0, הוא קיבוץ ספרות רגיל ואינו משנה דבר
  5. משאירים מקטעים לא מספריים במנוחה. מקטעי General, תאריך ושעה (כולל elapsed‏ [h], [mm] ו-[ss]), מקטעים מדעיים, שברים וטקסט, ומקטעים בלי אף ממלא מקום של ספרה שומרים על דיוק מלא
דיאגרמת HotXLS של כללי הדיוק המוצג: בוחרים את מקטע הפורמט לפי סימן הערך, סופרים את ממלאי המקום של הספרות אחרי הנקודה העשרונית, מוסיפים שתי ספרות עשרוניות לכל סימן אחוז, מחסירים שלוש לכל פסיק קניית מידה לאלפים כך שהספירה יכולה להיעשות שלילית, מדלגים לגמרי על מקטעי General ותאריך-שעה, ואז מעגלים חצי בכיוון הרחוק מהאפס
ספירת הספרות מגיעה מהמקטע שתואם את הסימן, בתוספת שתיים לכל אחוז ופחות שלוש לכל פסיק קניית מידה, וספירה שלילית מעגלת אל עשרות או מאות; מקטעי General ותאריך נשארים במנוחה

נמדד מול Excel 16, אלה הערכים ששני מנועי HotXLS שומרים עכשיו עבור תוצאת נוסחה בכל פורמט:

פורמט מספרערך מחושבערך שנשמרהכלל שחל
0.0%0.12340.123ספרה עשרונית אחת בתוספת שתיים עבור סימן האחוז
02.53חצי בכיוון הרחוק מהאפס, לא אל הזוגי
0-2.5-3חצי בכיוון הרחוק מהאפס גם בצד השלילי
0.00;(0.0)-1.2345-1.2המקטע השלילי מציג ספרה עשרונית אחת
0.00;(0.0)1.23451.23המקטע החיובי מציג שתי ספרות עשרוניות
#,##0.01234.56781234.6פסיק קיבוץ, בלי קניית מידה
0.0,12345.67812300ספרה אחת פחות שלוש: עיגול אל המאות
0.0%;(0.00%)-0.0125-0.0125המקטע השלילי שומר שתיים בתוספת שתי ספרות עשרוניות
0.001.0051.01סובלנות לשגיאת הייצוג הבינארי
0;-0;0.00.51אינו אפס, ולכן המקטע החיובי מכריע

השורה האחרונה היא מלכודת נחמדה. הערך 0.5 מעוגל אל מספר שלם, ומקטע האפס לעולם לא נכנס לפעולה, כי Excel בוחר את המקטע מהערך המחושב לפני העיגול. מגבלה כנה אחת בצד של HotXLS: מקטעים נבחרים לפי סימן בלבד, ולכן פורמט שהמקטעים שלו נושאים תנאי סוגריים מותאמים כמו [>=1000] עדיין מחולק לפי סימן. בדקו פורמטים כאלה מול Excel אם הם חשובים לכם

מדוע 1.005 מעוגל ל-1.01 ולא ל-1.00?

Excel מעגל 1.005 בתא 0.00 אל 1.01 למרות שה-double הקרוב ביותר אל 1.005 יושב מעט מתחת לנקודת החצי, ו-HotXLS משתווה לזה עם סובלנות של כמה ulp. הליטרל 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 מהערך המוקנה (כמה ulps בסדר גודל הזה, לעולם לא פחות משני ulps של 1.0), חותך, מקנה מידה בחזרה ומשחזר את הסימן. הפונקציה הבאה היא המחשה עצמאית של העיקרון, לא קוד הספרייה עצמו, והיא מטפלת בספירות ספרות שליליות עבור פסיקי קניית מידה באותה דרך:

דיאגרמת העיגול של HotXLS: 2.5 מעוגל חצי בכיוון הרחוק מהאפס אל 3 ו-‎-2.5 אל -3, שם System.Round של Delphi נותן את התשובות הבנקאיות 2 ו-‎-2, ומכיוון שה-double הקרוב ביותר אל 1.005 יושב מעט מתחת לנקודת החצי, דווקא הסובלנות של כמה ulp היא שהופכת 1.00 מבוסס floor אל התשובה של Excel‏ 1.01
Excel מעגל שוויונות בכיוון הרחוק מהאפס וסולח על שגיאת ייצוג בינארי עם סובלנות קטנה; שני הפרטים ניתנים למדידה, ודילוג על אחד מהם שומר 2 עבור 2.5 או 1.00 עבור 1.005, סנט אחד מ-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, שני ulps של 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; // הקניית המידה הייתה גולשת
    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 ספרות)
// RoundAsDisplayed(12345.678, -2) = 12300  ("0.0,": 1 - 3 ספרות)

הסובלנות היא פשרה מכוונת. ערך שבאמת יושב שני ulps מתחת למדרגת חצי יעוגל גם כן כלפי מעלה, אבל במרחק הזה ההבדל בלתי ניתן להבחנה משגיאת ייצוג, והתייחסות אליו בתור מדרגת חצי היא מה שגורם לעשרוניים שהוקלדו להתנהג כפי שמשתמשים מצפים

מה השתבש לפני v2.384.57?

לפני v2.384.57 למנוע ה-XLSX ולמנוע הקלאסי היה כל אחד קוד precision-as-displayed משלו, וכל אחד היה שגוי בדרך אחרת. אם אתם מפיקים חוברות עבודה כשהאפשרות דלוקה, אלה הסימפטומים לחפש בקבצים שנוצרו ב-builds ישנים

מנוע XLSX: המקטע הראשון בלבד, בלי אחוז, עיגול בנקאי

נתיב ה-XLSX הישן ביקש את ספירת הספרות העשרוניות של מחרוזת הפורמט כולה, מה שהביט רק במקטע הראשון והתעלם מ-%, ואז עיגל עם Round. 0.1234 ב-0.0% נשמר בתור 0.1, שהוא 10% במקום ה-12.3% על המסך. 2.5 ב-0 נשמר בתור 2 במקום 3. ערכים שליליים בפורמט כמו 0.00;(0.0) עוגלו אל שתי הספרות העשרוניות של המקטע החיובי. מאז v2.384.57 מנוע ה-XLSX קורא לאותה רוטינה משותפת כמו המנוע הקלאסי, שגם קיבל תמיכה בפסיק קניית מידה באותה מהדורה

המנוע הקלאסי: TRUE נהיה -1

המנוע הקלאסי הגן על העיגול שלו עם VarIsNumeric, ו-VarIsNumeric מחזיר True גם עבור Variant של varBoolean. המרת ה-Variant הזה עם Double(V) מניבה -1, כי Boolean True בסגנון COM נשמר בתור -1. נוסחה כמו =A1>0 בתא שמעוצב 0.00 לכן יצאה מהחישוב מחדש בתור המספר -1. מאז v2.384.57 תוצאות Boolean נשללות לפני כל בדיקה מספרית, ותוצאה לוגית נשארת תוצאה לוגית בשני המנועים

פורמטי זמן שחלף נקראו בתור צבעים (v2.384.9)

הבאג השלישי ישב במודל פורמט המספר ולא בעיגול. המפרסר סיווג כל token מסוגר שאינו תנאי בתור צבע, ולכן [h], [mm] ו-[ss] מעולם לא סימנו את המקטע שלהם בתור תאריך/שעה. התצוגה לא נפגעה, כי העיצוב רץ על נתיב נפרד, אבל precision as displayed נשען על הדגל הזה כדי לדלג על ערכי זמן. משך של חמש שניות הוא 5/86400 מיום, כלומר כ-0.0000579, ופורמט כמו [ss].00 נראה כמו מספר עשרוני רגיל בן שתי ספרות, ולכן כש-FullPrecision כבוי משך הזמן עוגל אל 0.00 ימים. מאז v2.384.9 רצף מסוגר של אות h, m או s בודדת מפורסר בתור token של זמן שחלף והמקטע מטופל בתור תאריך/שעה. אותה מהדורה תיקנה זיהוי דקות ב-h:mm, שבו הנקודתיים בין ה-tokens הסתירו את השעה מהמפרסר

דיאגרמת HotXLS של פרסור שגוי של זמן שחלף: חמש שניות נשמרות בתור שבר יום זעיר בתא שמעוצב עם token ה-ss המסוגר, שהמפרסר הישן קרא בתור צבע וסימן בתור מספר עשרוני רגיל בן שתי ספרות, ולכן precision as displayed עיגל את משך הזמן אל 0.00 עד שהוא פורסר כמקטע זמן שחלף
העיצוב רץ על נתיב משלו, ולכן התא נראה נכון בזמן שהערך השמור עוגל לאפס; רצף מסוגר של אות בודדת h, m או s הוא token של זמן שחלף ולא צבע, והמקטע שומר על דיוק מלא

הפעלת precision as displayed ב-HotXLS מ-Delphi

כדי לקבל ערכים שמורים השקולים ל-Excel, מגדירים את הדגל לפני החישוב מחדש שצריך לכבד אותו, ואז קוראים את התוצאות המטמוניות או שומרים. במנוע ה-XLSX, 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
    Wb.FullPrecision := False;
    Wb.Recalculate;

    // התוצאות במטמון עכשיו תואמות 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;

המנוע הקלאסי מתנהג אותו דבר, עם נוחות אחת: שיוך TXLSWorkbook.UseFullPrecision מסמן כל נוסחה בגרף התלויות כ-dirty, ולכן ה-Recalculate הבא מחשב מחדש את כל חוברת העבודה תחת הכלל החדש. שינוי NumberFormat כשהאפשרות דלוקה מסמן גם הוא את תאי הנוסחה המושפעים כ-dirty, כי הפורמט עכשיו מכריע את הערך השמור. שימו לב שה-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: המקטע השלילי "(0.0)" מציג ספרה עשרונית אחת
    // C1 נשאר Boolean True (builds לפני v2.384.57 שמרו -1)
    Wb.SaveAs('report.xls'); // רשומת CalcPrecision עם fFullPrec = 0
  finally
    Wb.Free;
  end;
end;

שני המנועים גם מכבדים את הדגל שמגיע עם קובץ. פתחו חוברת עבודה שנשמרה כשהאפשרות דלוקה ו-FullPrecision או UseFullPrecision כבר False, ולכן Recalculate אחרי טעינה מעגל בדיוק כפי ש-Excel היה מעגל. אם צריך רק לקרוא את המספרים ש-Excel כבר שמר, אפשר לדלג על חישוב מחדש לגמרי, כמתואר ב-קריאת ערכי נוסחה מטמוניים בלי חישוב מחדש. לגבי איך מספרים סידוריים ופורמטי תאריך מתקשרים עם מודל הפורמט שמניע את בדיקת התאריך/שעה, ראו את מספרים סידוריים של תאריך ב-Excel, מערכת 1904 ו-numFmt ב-Delphi

מתי כדאי להדליק precision as displayed, ומתי לא?

מדליקים precision as displayed רק כשהמספרים השמורים של חוברת העבודה חייבים להשתוות למספרים המוצגים שלה, ומקבלים לאבד את הספרות הנוספות לתמיד. המקרה הלגיטימי הקלאסי הוא לוח זמנים פיננסי שבו עמודות של סכומים מעוגלים חייבות להסתכם לסכום המעוגל על המסך, בלי שברי סנט נסתרים שמפיקים סכום שחורג באחד בספרה האחרונה. התאמה לחוברת עבודה קיימת של לקוח שכבר מפעילה את האפשרות היא הסיבה הטובה השנייה, ו-HotXLS שומר על הדגל ב-round-trip כדי שלא תחזירו אותם בשקט אל דיוק מלא

נמנעים ממנו ברוב המצבים האחרים:

  • נתוני הנדסה ומדע. עיגול מדידה כי מישהו בחר פורמט של שתי ספרות עשרוניות עבור דוח משמיד מידע ששום שינוי פורמט מאוחר לא יכול לשחזר
  • אחוזים עם פורמטים גסים. פורמט 0% שומר רק שתי ספרות עשרוניות של היחס השמור, ולכן 0.1234 נהיה 0.12, וכל נוסחה במורד הזרם שקוראת את התא עובדת עם 0.12
  • תצוגות ממוקנות. פורמט 0, או 0.0, שמשמש להצגת אלפים מעגל את הערך השמור אל האלפים או המאות, מה שלעיתים רחוקות הוא מה שמי שבחר את הפורמט התכוון
  • תבניות משותפות. הדגל חל על כל חוברת העבודה. כל מי שיוסיף גיליון אחר כך יורש את ההתנהגות, בדרך כלל בלי לדעת שהיא דלוקה

אם מה שרוצים באמת הם תוצאות מעוגלות בכמה תאים ספציפיים, כותבים ROUND לתוך אותן נוסחאות במקום. ROUND מפורש, מקומי לתא, גלוי לכל מי שקורא את הנוסחה, ומחושב על ידי מנוע הנוסחאות של HotXLS כמו כל פונקציה אחרת, בלי תופעות לוואי ברמת חוברת העבודה

עזר זריז ל-precision as displayed

  • דגל בקובץ: CalcPrecision $000E עם fFullPrec = 0 ב-BIFF8 ([MS-XLS] §2.4.35), calcPr fullPrecision="0" ב-XLSX (ECMA-376 חלק 1)
  • מתגי HotXLS: TXLSXWorkbook.FullPrecision := False ו-TXLSWorkbook.UseFullPrecision := False, שניהם כברירת מחדל True
  • מקטע: נבחר לפי הסימן של הערך המחושב; המקטע השלישי רק עבור אפס בדיוק
  • ספרות: ממלאי מקום עשרוניים, בתוספת שתיים לכל %, פחות שלוש לכל פסיק קניית מידה; הספירה יכולה להיות שלילית
  • עיגול: חצי בכיוון הרחוק מהאפס עם סובלנות של כמה ulp, ולכן 2.5 נותן 3, -2.5 נותן -3 ו-1.005 נותן 1.01
  • מדולגים: General, תאריך/שעה וזמן שחלף, מדעי, שבר, טקסט, Boolean וערכי שגיאה
  • היקף ב-HotXLS: תוצאות נוסחה בזמן חישובן; קבועים נשמרים כפי ששויכו
  • מנוע XLSX: מגדירים FullPrecision לפני ה-Recalculate הראשון; ה-setter הקלאסי מסמן מחדש את כל הנוסחאות בעצמו
  • גרסאות: תואם ל-Excel 16 בשני המנועים מאז v2.384.57; פורמטי זמן שחלף מוגנים מאז v2.384.9

HotXLS קורא, כותב ומחשב חוברות עבודה של XLS ו-XLSX באופן טבעי מ-Delphi ומ-C++Builder, כולל אפשרויות חישוב חוברת העבודה שכוסו כאן. פרטים, מהדורות והורדת ניסיון נמצאים ב-דף רכיב הגיליונות HotXLS ל-Delphi