בעיית דיוק מאוד מוזרה ב-Java (עם float) - תכנות - HWzone פורומים
עבור לתוכן
  • צור חשבון

בעיית דיוק מאוד מוזרה ב-Java (עם float)


lharpaz

Recommended Posts

שימו לב לקוד הפשוט הבא:

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

מישהו מכיר את הבעיה? יודע איך פותרים אותה? יודע למה זה קורה??

קישור לתוכן
שתף באתרים אחרים

אני לא בטוח שזה יפתור את הבעיה.

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

מה שקורה הוא שנוצר אי דיוק שמצטבר (כלומר, k לא גדל בדיוק ב-0.1 כל פעם אלא במשהו כמו 0.100000002)

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

יש כמה פתרונות:

1. לא להשתמש בשברים, אלא להגדיר i שלם שירוץ מ-0 עד 20, ובתוך הלולאה להגדיר k=(float)i/10

2. כל פעם לעגל את k לכפולה של 0.1 (אני לא בטוח שג'אווה מאפשר את זה בצורה טריוויאלית, כי הפונקציה round מעגלת רק לשלמים)

3. אני מניח שאפשר לגרום לו להדפיס ברמת דיוק יותר נמוכה (ואז 0.9000001 יהפוך ל-0.9), אבל אז k עדיין לא יהיה מדויק.

קישור לתוכן
שתף באתרים אחרים

ב-double יש את אותה הבעיה.

ועוד יותר מוזר, החישוב של 0.6+0.1 עדיין נותן תוצאה לא מדוייקת...

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

תודה בכל מקרה.

קישור לתוכן
שתף באתרים אחרים

לעבוד עם float/double זה אומר בהכרח להתמודד עם שגיאות דיוק.

אתה לא אמור להשוות בין שני floats/double בשום מקרה ע"י '=' אלא ע"י abs(x-y)<eps

(כאשר eps הוא איזשהו מספר קטן מאוד)

הפיתרון הראשון שהוצע נשמע לי הכי הגיוני (כי השגיאה בו לא מצטברת).

קישור לתוכן
שתף באתרים אחרים

ארכיון

דיון זה הועבר לארכיון ולא ניתן להוסיף בו תגובות חדשות.

×
  • צור חדש...