0.1+0.2 = ?

חידה קטנה: אם אני עושה בשפת מחשב (כולל מסדי נתונים) את החישוב הבא:

0.1+0.2

מה תהיה התוצאה ?

התשובה היא שזה תלוי.

במה זה תלוי ? ובכן זה תלוי במהדר/מפרש, וזה תלוי בסטנדרט שאותו מפרש/מהדר משתמש בו.

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

מבחינת מסדי נתונים כל מה שניסיתי (שזה Firebird, MySQL, PosgreSQL) כולם נתנו תשובה זהה לFPC.

שאר השפות החליטו שמדובר בתוצאה של 0.30000000000000004

מהם שאר השפות ?

ובכן

C (gcc), Perl, Ruby, Python, Javascrupt (Firefox), PHP

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

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

12 מחשבות על “0.1+0.2 = ?

  1. Shai

    צפריר, לשאלתך:

    $ python
    Python 2.5.5 (r255:77872, Feb 1 2010, 19:53:42)
    [GCC 4.4.3] on linux2
    Type "help", "copyright", "credits" or "license" for more information.
    >>> 0.1 + 0.2
    0.30000000000000004
    >>> print 0.1+0.2
    0.3

    עידו: אף אחת מהשפות שציינת לא מממשת בעצמה את העבודה עם נקודה צפה (אני מקווה…), כולם סומכים על המעבד. 0.3 הוא שבר שאינו ניתן לביטוי בצורה מדוייקת בשיטה המקובלת (IEEE754), ולכן, ההבדלים שאתה רואה הם לא בין תוצאות החישובים אלא בין צורות ההדפסה של התוצאה.

  2. ik_5 מאת

    הבדיקה שלי (בלי קשר להדפסה) היתה פשוטה:

    if (0.1+0.2) = 0.3 then
    writeln('Yes')
    else
    writeln('No');

    בכל השפות והסביבות, בהתאם לצורה שהשפה סיפקה לי.

    חשוב לי לציין שעצם זה ש FPC אמרה שהתשובה היא "כן", זה גם מזל נטו וכמו ששי אמר מבוסס על המעבד.

    אני עובד על מעבד אבל של 64 ביט אולי זה מה שמשפיע, ולא עשיתי שום אופטימיזציה בשום שפה וגישה שעבדתי בה.

  3. Shai

    הבנתי מה הולך כאן: קבועים כמו 0.1 שמופיעים בפסקל הם, כברירת מחדל, במה שנקרא "דיוק יחיד" (float ב־C). בשפות האחרות הם ב"דיוק כפול" (double). למרות שבבחינה שבחרת, זה יוצא "לטובת" פסקל, זה לא עניין להתגאות בו, להיפך.

    ב־C, כדי לקבל את ההתנהגות הפסקלית, בדוק אם 0.1f+0.2f==0.3f.

  4. ik_5 מאת

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

    גם שימוש בהגדרות כמו http://www.freepascal.org/docs-html/prog/progsu49.html#x56-540001.1.49
    יכולות מאוד להשפיע על ההתוצאה.

    ד"א לדעתי בברירת מחדל הוא השתמש דווקא ב single ולא ב double בפסקל.

  5. Shai

    כן, זה מה שכתבתי: פסקל, כברירת מחדל, השתמשה ב־single. כל השאר ב־double. ב־C, כדי לקבל single, אתה צריך לשים f בסוף המספר.

    ואני חוזר: זה לא משהו שפסקל צריכה להתגאות בו. זה שריד ארכאי, התנהגות שמתאימה למעבדים של לפני 30 שנה. היום, אתה רואה float־ים כמעט רק בתחומים ספציפיים — embedded או גרפיקה (המעבד הוא לא CPU סטנדרטי) או משחקים (הדיוק פחות חשוב מכמות הזיכרון בגלל כמות הנתונים, ובהרבה מקרים גם ה־GPU מעורב). בשפה שטוענת להיות General-Purpose, זה מוזר, על גבול ה־Gotcha.

  6. ik_5 מאת

    כמו שכתבתי למעלה, ההגדרה הזו משתנה בהתאם להרבה דברים כמו סוג מעבד והגדרות שונות. אפילו שינוי דיאלקט השפה ישנה את ההתנהגות הזו.

    וה"שריד" הזה, שונה מאוד למשל מ TP, אבל עצם זה שבשאר השפות בוחרים בconstants שהם מאוד ברורים דווקא כמות ביטים גבוהה יותר משצריך אומר שהן מאוד מבזבזות את הזיכרון, ואח"כ מתפלאים למה מערכות צריכות היות מינימום 4 גיגה זיכרון על כלום. איפה הימים בהם תוכנה שלמה עם המון פיטצ'רים היתה עולה על דיסקט 1.44 עם הרבה מקום פנוי ו64 קי נחשב משהו שרק עשירים יכולים לחשוב עליו ?

    אני מתגעגע לימים האלו כי אז היתה הרבה חשיבה, היום אני מדבר עם מתכנתים ואומר להם כמה SOAP (למשל) עודף בזבזני ולא ידידותי בשיט, והם "מה הבעיה, כמה פקודות ב C# וזה עובד".

  7. סוייר

    העניין, כפי שצוין, הוא שרוב השפות עושות
    floating point arithmetics
    כברירת מחדל

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

    אני יכול להגיד לך שלקרוא את מסמך המהנדסים של סאן בנושא לא היה כזה כיף🙂

    בפרל, דרך אגב, פשוט צריך לעשות
    use integer

  8. ik_5 מאת

    הבעיה עם נקודות צפות היא שלוקחים זיכרון של מספר שלם ומחלקים אותו לסגמנטים שחלקם בנויים לחלק השלם והשאר לציפה. השיטה הזו נקראת שיטה בינארית. הגישה הבינארית המקובלת אבל מיושנת משנותה 60, והתאימה לגישה של מחשבים בשנות ה 60-70 כיום אמורים להיות ברוב מעבדי אינטל (ותואמיהם) אפשרות לעבוד בעוד שיטות, הבעיה היא שהסטנדרט שעדיין קובע זה הסטנדרט משנות ה 60 וחבל.

  9. פינגבק: איך אתם עושים את זה בשפה שלכם ? « לראות שונה

כתיבת תגובה

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

הלוגו של WordPress.com

אתה מגיב באמצעות חשבון WordPress.com שלך. לצאת מהמערכת / לשנות )

תמונת Twitter

אתה מגיב באמצעות חשבון Twitter שלך. לצאת מהמערכת / לשנות )

תמונת Facebook

אתה מגיב באמצעות חשבון Facebook שלך. לצאת מהמערכת / לשנות )

תמונת גוגל פלוס

אתה מגיב באמצעות חשבון Google+ שלך. לצאת מהמערכת / לשנות )

מתחבר ל-%s