John Squirrels
רָמָה
San Francisco

NaN ב-Java

פורסם בקבוצה
ב-Java, "NaN" מייצג "לא מספר". זה לא סוג של חריג, באופן מפתיע, גם סוג הנתונים של NaN הוא מספר. אבל לעתים קרובות כאשר מתכנתים מתחילים מקבלים את זה בלי כוונה, הם עוד משתמשים בזה בחישובים שלהם. מכאן שסוגי נתונים לא תואמים ב-Java בשימוש יחד עלולים לגרום לשגיאה שניתן לזרוק. זה גם נפוץ לראות שנחשב java.lang.ArithmeticException: / by zeroזהה ל-NaN. עם זאת, Java מתייחסת לשניהם בצורה שונה. מספיק תמוה? להבנתך המקיפה, ננתח כיצד אלה שונים זה מזה. בסוף מאמר זה תלמדו על הפעולות האפשריות שמפיקות לא מספר (nan), וכמה דרכים קלות לטפל בזה.

מה זה NaN?

אז מה זה NaN? "NaN" כפי שרבים מכם ניחשו, משמש לייצוג "Not a Number" ב-Java. זהו ערך מיוחד של נקודה צפה לציון הצפות ושגיאות. זה נוצר כאשר מספר נקודה צפה מחולק באפס או אם השורש הריבועי של מספר שלילי מחושב. NaN ב-Java - 1לדוגמה, עיין בקטע הבא.
public class NaN
{
    public static void main(String[]args)
    {
        System.out.println(0.0 / 0.0);	  //zero divided by zero
        System.out.println(Math.sqrt(-1)); //take sqrt of negative number
        System.out.println(10.0 % 0);      //taking mod by zero
    }
}
תְפוּקָה

NaN                                                                                                                                           
NaN                                                                                                                                           
NaN
בקטע למעלה, אתה יכול לראות ש-NaN נוצר כתוצאה מ-3 פעולות פשוטות:
  • חלוקת float / doubleאפס באפס.
  • נטילת מתחת לשורש של מספר שלילי (Math.sqrt(-x)). במתמטיקה, לקיחת השורש הריבועי של מספר שלילי מביא למספר דמיוני . מקרה זה מטופל על ידי החזרת NaN ב-Java.
  • נטילת מוד של מספר עם אפס, תחזיר את השארית לאחר חלוקת ערך באפס. לפיכך, NaN מוחזר.

במה שונה NaN מאינסוף חיובי ושלילי?

על פי מפרט IEEE 754, ישנם שלושה ערכים מיוחדים של נקודה צפה וערכים כפולים לטיפול במקרי הגבול:
  • אינסוף חיובי
  • אינסוף שלילי
  • NaN
התוצאה של חלוקת מספר חיובי ב-0 היא אינסוף חיובי. באופן דומה, אינסוף שלילי מניב כתוצאה מחלוקת מספר שלילי באפס. שים לב שכל ערכי הנקודה הצפה חלים גם על סוג נתונים כפול. הדיוק המוגבל של מצופים אינו מספיק לפעמים. עם זאת, נראה כיצד NaN עובד עבור ציפה וכפולה בסעיף מאוחר יותר.

מהי שיטת NaN()?

isNaN()היא אחת השיטות הבסיסיות ב-Java לבדוק אם זה ערך NaN או לא. כפי שדנו בשלושה מקרים לעיל, הגיע הזמן לבדוק כיצד שיטת isNaN() מבדילה בין ערכי +infinity , -infinity ו-NaN.
public class isNaN
{ public static void main(String[]args)
  {
    Double posInfinity = +2.0 / 0.0;
    Double negInfinity = -3.5 / 0.0;
    Double nanVal = 50 % 0.0;


    System.out.println ("+" + posInfinity + ".IsNaN() = " + posInfinity.isNaN());
    System.out.println ( negInfinity + ".IsNaN() = " + negInfinity.isNaN());
    System.out.println ( nanVal +  ".IsNaN() = " + nanVal.isNaN());
  }
}
תְפוּקָה

+Infinity.IsNaN() = false                                                                                                                       
-Infinity.IsNaN() = false                                                                                                                       
NaN.IsNaN() = true

כיצד להשוות ערכי NaN?

כל ערך NaN נחשב למובחן. משמעות הדבר היא, שאף NaN לא שווה לכל NaN אחר. לפי העיקרון הזה, אם אתה משווה ערך אחד למשנהו התוצאה תמיד שלילית. מכיוון ש- NaN אינו מסודר, כך שהשוואה מספרית הכוללת אפילו NaN בודד מחזירה שקר. Java מספקת Float.NaN ו-Double.NaN עבור שדות קבועים בשתי המחלקות לביצוע השוואות. אנו יכולים להבדיל בין אלה בשני תרחישים נפרדים:
  • נכון: רק במקרה של חוסר שוויון (!=)
  • שקר: עבור כל אופרנדים להשוואה (==, <=, >=, <, >)
הנה דוגמה עובדת עבורכם:
public class ComparingNaN
{ public static void main(String[] args)
  {
    // Comparing NaN values for Float constants
    System.out.println (Float.NaN != Float.NaN); // true
    System.out.println (Float.NaN == Float.NaN); // false
    System.out.println (Float.NaN < Float.NaN);  // false
    System.out.println (Float.NaN > Float.NaN);  // false
    System.out.println (Float.NaN <= Float.NaN); // false
    System.out.println (Float.NaN >= Float.NaN); // false

    // Comparing NaN values for Float constants
    System.out.println (Double.NaN != Double.NaN); // true
    System.out.println (Double.NaN == Double.NaN); // false
    System.out.println (Double.NaN < Double.NaN);  // false
    System.out.println (Double.NaN > Double.NaN);  // false
    System.out.println (Double.NaN <= Double.NaN); // false
    System.out.println (Double.NaN >= Double.NaN); // false
  }
}

כיצד ליצור ערכי NaN?

לפני סיום, הבה נסתכל על כמה דוגמאות נפוצות לקבלת ה-Not a Number (nan).
public class GenerateNaNValues {
  static final float ZERO = 0;
  public static void main (String[]args)
  {
    System.out.println("ZERO / ZERO = " + (ZERO / ZERO));
    System.out.println("+INFINITY - INFINITY = " +
    (Float.POSITIVE_INFINITY + Float.NEGATIVE_INFINITY));
    System.out.println("-INFINITY * ZERO = " + (Float.NEGATIVE_INFINITY * ZERO));
    System.out.println("+INFINITY * ZERO = " + (Float.POSITIVE_INFINITY * ZERO));
    System.out.println("log10(-10) = " +  Math.log(-10));
    System.out.println("√-10 = " + Math.sqrt(-10));
    System.out.println("NaN + 10 = " + (Float.NaN + 10));
    System.out.println("NaN - 10 = " + (Float.NaN - 10));
    System.out.println("NaN * 10 = " + (Float.NaN * 10));
    System.out.println("NaN / 10 = " + (Float.NaN / 10));
    System.out.println("NaN + NaN = " + (Float.NaN + Float.NaN));
    System.out.println("NaN - NaN = " + (Float.NaN - Float.NaN));
    System.out.println("NaN * NaN = " + (Float.NaN * Float.NaN));
    System.out.println("NaN / NaN = " + (Float.NaN / Float.NaN));
  }
}
תְפוּקָה:

ZERO / ZERO = NaN                                                                                                                               
+INFINITY - INFINITY = NaN                                                                                                                      
-INFINITY * ZERO = NaN                                                                                                                          
+INFINITY * ZERO = NaN                                                                                                                          
log10(-10) = NaN                                                                                                                                
√-10 = NaN                                                                                                                                      
NaN + 10 = NaN                                                                                                                                    
NaN - 10 = NaN                                                                                                                                  
NaN * 10 = NaN                                                                                                                                  
NaN / 10 = NaN                                                                                                                                  
NaN + NaN = NaN                                                                                                                                 
NaN - NaN = NaN                                                                                                                                 
NaN * NaN = NaN                                                                                                                                 
NaN / NaN = NaN

סיכום

לאחר שתסתכל על הפעולות הרבות שמייצרות NaN, אתה חייב להכיר את זה עכשיו. זה עשוי להפתיע אותך בהתחלה, אבל אין שום דבר מסובך להתמודד עם זה. על ידי פיתוח הרגל קטן לבדוק אם ערך אינו NaN בחישובי נקודה כפולה/צפה יכול לחסוך ממך טרחה רבה. גם אם תשכח את זה בהתחלה, זה בסדר גמור. אתה תמיד יכול לעיין במאמר זה לפתרון בעיות קלות. יצירת קוד ניתן להתאמה וללא שגיאות במכה אחת מגיעה לאחר שנים של ניסיון. אז בואו ללכלך את הידיים בקוד, ונבנה משהו נהדר!
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION