פורסם 2005 במאי 1620 שנים שימו לב לקוד הפשוט הבא:for (float k=0; k<=2; k+=0.1) { System.out.print(k + " "); }ושימו לב לפלט:0.0 0.1 0.2 0.3 0.4 0.5 0.6 0.70000005 0.8000001 0.9000001 1.0000001 1.1000001 1.2000002 1.3000002 1.4000002 1.5000002 1.6000003 1.7000003 1.8000003 1.9000003 מישהו מכיר את הבעיה? יודע איך פותרים אותה? יודע למה זה קורה??
פורסם 2005 במאי 1620 שנים אני לא בטוח שזה יפתור את הבעיה.הבעיה נובעת מחוסר הדיוק של המחשב בהצגת שברים - בהצגה בינארית, 0.1 הוא בעצם שבר אינסופי (והמחשב יכול להציג רק מספר מוגבל של ביטים).מה שקורה הוא שנוצר אי דיוק שמצטבר (כלומר, k לא גדל בדיוק ב-0.1 כל פעם אלא במשהו כמו 0.100000002)כשאי הדיוק קטן מספיק, ג'אווה מתעלם ממנו, אבל כשהוא מספיק גדול הוא מציג אותו.יש כמה פתרונות:1. לא להשתמש בשברים, אלא להגדיר i שלם שירוץ מ-0 עד 20, ובתוך הלולאה להגדיר k=(float)i/102. כל פעם לעגל את k לכפולה של 0.1 (אני לא בטוח שג'אווה מאפשר את זה בצורה טריוויאלית, כי הפונקציה round מעגלת רק לשלמים)3. אני מניח שאפשר לגרום לו להדפיס ברמת דיוק יותר נמוכה (ואז 0.9000001 יהפוך ל-0.9), אבל אז k עדיין לא יהיה מדויק.
פורסם 2005 במאי 1720 שנים מחבר ב-double יש את אותה הבעיה.ועוד יותר מוזר, החישוב של 0.6+0.1 עדיין נותן תוצאה לא מדוייקת...רעיון מס' 1 לא רע - סביר שהוא יעבוד וגם נוח יחסית לעבוד איתו, אבל בנתיים אני עובד עם משהו אחר: יש לי מערך עם 11 הערכים המדוייקים שאני צריך, ואני פשוט משתמש בערכים במערך הזה. זה מכוער, אבל זה עובד...תודה בכל מקרה.
פורסם 2005 במאי 1720 שנים לעבוד עם float/double זה אומר בהכרח להתמודד עם שגיאות דיוק.אתה לא אמור להשוות בין שני floats/double בשום מקרה ע"י '=' אלא ע"י abs(x-y)<eps (כאשר eps הוא איזשהו מספר קטן מאוד)הפיתרון הראשון שהוצע נשמע לי הכי הגיוני (כי השגיאה בו לא מצטברת).
ארכיון
דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.