סוג נתון: Decimal

30/04/2013

תגובה אחת

כשמטפלים במספרים גדולים מאוד מבחינת ערכם המוחלט (כלומר- מספר הספרות משמאל לנקודה) או קטנים מאוד מבחינת ערכם המוחלט (כלומר- מספר הספרות מימין לנקודה) – Decimal הוא אפשרות שתספק את רוב צרכינו; כולל מקרים בהם יש לטפל במספרים שלמים גדולים מאוד שאפילו BigInt מרים ידיים לעומתם..
סוג הנתון הזה מקבל שני פרמטרים המציינים כמה ספרות בסה"כ וכמה מתוכן מימין לנקודה. למשל (Decimal(38,12 מציין שניתן לדייק עד 12 ספרות מימין לנקודה (שברים עשרוניים) ועד 38-12=26 ספרות משמאל לנקודה:

Declare @I Decimal(38,12)=12345678901234567890123456.123456789012;

Select  @I;

clip_image002

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

Declare @I Decimal(38,12)=12345678901234567890123456.123456789012;

Select  @I/1000000;

Select  @I*1000000;

clip_image004

כשחילקנו במיליון – הדיוק של 12 ספרות מימין נותר בעינו, וכתוצאה מכך 6 ספרות "הלכו לאיבוד";

וכשכפלנו במיליון – המערכת הקצתה לנו עוד 6 ספרות משמאל אך "קנסה" אותנו ב-6 ספרות מימין.

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

(אם נבצע את התרגיל הנ"ל בעזרת עשרה מיליון – פעולת הכפל תיכשל: זה לא תמיד עובד!)

יחד עם זאת, ל-Decimal יש כמה פינות אפלות. שורו נא:

Declare @A Decimal(38,10)=22,

        @B Decimal(38,10)=7;

Declare @A Decimal(38,10)=1000,

        @B Decimal(38,10)=1024;

Select  @A [A],

        @B [B],

        @A+@B [A+B],

        @A-@B [A-B],

        @A*@B [A*B],

        @A/@B [A/B],

        @A/@B*@B [A/B*B];

clip_image006

בשתי העמודות הראשונות אנחנו רואים ששני המשתנים קיבלו את מספר הספרות המבוקש מימין לנקודה (10).

כשמחברים או מחסירים אותם (העמודות השלישית והרביעית) – מתקבלת התוצאה המבוקשת בדיוק המבוקש,

אך כשכופלים או מחלקים (העמודות החמישית והשישית) מקבלים משום מה דיוק של 6 ספרות מימין לנקודה, כשבמקרה של החילוק זה קריטי כי מידע הולך לאיבוד! ניתן לראות זאת בעמודה השביעית: את A חילקנו ב-B וכפלנו ב-B, לכאורה היינו אמורים לקבל חזרה את A=1000, אלא שבחלוקה סיפרה אחת מימין הלכה לאיבוד (צריך להיות 0.9765625 ולא 0.976562) והמכפלה לא החזירה אותנו לנקודת המוצא.

מה עושים? פתרון אפשרי במקרה זה – קודם לכפול ולאחר מכן לחלק (יש מספיק מקום משמאל לנקודה):

Declare @A Decimal(38,10)=1000,

        @B Decimal(38,10)=1024;

Select  @A [A],

        @B [B],

        @A*@B/@B [A*B/B];

clip_image008

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

רעיון חלופי שעולה בדעתנו הוא להקצות יותר מקום מימין לנקודה, במקום 10 ספרות נקצה 20 ספרות:

Declare @A Decimal(38,20)=1000,

        @B Decimal(38,20)=1024;

Select @A [A],

        @B [B],

        @A/@B*@B [A/B*B];

clip_image010

הפלא ופלא: גם כשמקצים 20 מקומות מימין לנקודה – למנה יש דיוק של 6 ספרות בלבד.

רגע, ואם לכל מספר תהיה רמת דיוק אחרת?

Declare @A Decimal(38,20)=1000,

        @B Decimal(38,10)=1024;

Select  @A [A],

        @B [B],

        @A/@B [A/B],

        @A/@B*@B [A/B*B];

clip_image012

מה קורה כאן? נכון שדומה שהבעייה נפתרה, אבל מה החוקיות כאן? כיצד המערכת קובעת את רמת הדיוק במקרה של חלוקה של Decimals?

לא מדובר כאן בסתם סקרנות אינטלקטואלית: לעיתים יש להפיק דוחות שמתבצעים בהם חישובי ריבית או שיעורי רווח שמצריכים רמת דיוק גבוהה, במקרים אחרים מתעסקים בסכומים הנקובים במיליונים (נניח – 100 מציין מאה מיליון) ואז הספרה השביעית מימין אולי אינה משמעותית אך הדוחות עלולים לא להתאזן; ומה נסביר למנכ"ל? שה-Decimal גנב לנו כמה שקלים?..

ניסיתי לחקור את הסוגייה עד כמה שאפשר, והנוסחה הכי מדוייקת אליה הצלחתי להגיע היא זו:

MIN(1+X2+Y1,MAX(X2-Y2+Y1-X1,6,(38-MAX(X1,X2))+Y1-Y2))

כאשר המונה הוא (Decimal(X1,Y1 והמכנה הוא (Decimal(X2,Y2.

למשל:

Declare @A Decimal(26,5)=1000,

        @B Decimal(38,7)=1024;

Select  @A [A],

        @B [B],

        @A/@B [A/B];

clip_image014

X1=26

Y1= 5

X2=38

Y2= 7

MIN(1+38+5,MAX(38-7+5-26,6,(38-MAX(26,38))+5-7)) = 10

כפי שניתן לראות – למונה יש דיוק של 10 ספרות מימין לנקודה.

אם למישהו יש נוסחה מדוייקת ואלגנטית יותר – אשמח לשמוע, ובכל מקרה כדאי לבדוק היטב את הגדרות ה-Decimals אם המערכת מחזירה תוצאות מעוגלות ולא מדוייקות.

הוסף תגובה
facebook linkedin twitter email

כתיבת תגובה

האימייל לא יוצג באתר. שדות החובה מסומנים *

תגובה אחת

  1. http://www.swagsshoes.com24/07/2013 ב 23:28

    סוג נתון: Decimal – גרי רשף

    הגב