2017-05-12 4 views
8

Ich bin verwirrt wie Scala Division durch Null behandelt. Hier ist ein REPL-Code-Snippet.Scala Division durch Null ergibt unterschiedliche Ergebnisse

scala> 1/0 
java.lang.ArithmeticException:/by zero 
    ... 33 elided 

scala> 1.toDouble/0.toDouble 
res1: Double = Infinity 

scala> 0.0/0.0 
res2: Double = NaN 

scala> 0/0 
java.lang.ArithmeticException:/by zero 
    ... 33 elided 

scala> 1.toInt/0.toInt 
java.lang.ArithmeticException:/by zero 
    ... 33 elided 

Wie Sie im obigen Beispiel sehen können, je nachdem, wie Sie durch Null teilen, erhalten Sie eine der folgenden Möglichkeiten:

  • „java.lang.ArithmeticException:/durch Null“
  • "Double = NaN"
  • "Double = Infinity"

Das Debuggen besonders eine ziemliche Herausforderung macht, wenn sie mit Daten umzugehen unbekannte Merkmale. Was ist der Grund für diese Herangehensweise oder gar eine bessere Frage, wie man in Scala einheitlich mit der Division durch Null umgehen kann?

+1

Ich denke, das mit den verschiedenen Datentypen zu tun hat. Versuchen Sie immer dieselben Datentypen zu verwenden, wenn Sie andere, aber verwandte Berechnungen ausführen. Bsp .: Double, Int, etc – Titulum

+0

Sie haben es vielleicht mit Daten unbekannter Eigenschaften zu tun, aber in einer statisch typisierten Sprache wie Scala haben Sie es nicht mit Daten des unbekannten Typs zu tun. –

+0

@AlexeyRomanov Ich verstehe, was du meinst. Ich denke jedoch, die meisten Leute würden zustimmen, dass diese Art von Ansatz anfällig für einige sehr schmutzige Bugs sowie sehr mühsam in jeder arithmetischen Operation ist, die Sie schreiben. – Ahmedov

Antwort

17

Es ist alles auf die Division durch Null Regeln für verschiedene Arten.

0/0 ist eine ganzzahlige Division durch Null (wie beiden Argumente sind ganzzahlige Literale) und dass erforderlich ist, ein java.lang.ArithmeticException zu werfen.

1.toDouble/0.toDouble ist eine Gleitkomma Division durch Null mit einem positiven Zähler, und, was erforderlich ist, um +Infinity zu bewerten.

0.0/0.0 ist eine Gleitkommadivision durch Null mit einem Zähler von Null, und das ist erforderlich, um +NaN auszuwerten.

Die erste ist eine Java-und Scala-Konvention, die anderen beiden sind Eigenschaften von IEEE754 Fließkomma, was ist, was Java und Scala beide verwenden.

2

Doubles und Floats sind floating-point Werte (more here), die als +Infinity dargestellt werden kann und -InfinityNaN wie in IEEE 754 Standard definiert.
Integers sind fixed numbers, die haben keine Möglichkeit, explizit ungültige Daten anzeigt, so werfen sie exceptions
Einheitliche Lösung für dieses getOrElse Methode auf Try

Try(x/y).getOrElse(0) 

Im Falle wäre die Verwendung Sie wiederherstellen möchten nur auf ArithmeticException können Sie verwenden recover und get

Try(x/y).recover{ case _: ArithmeticException => 0 }.get 

recover können Sie Failure-Success
Sie auch Try-Option verwenden können, konvertieren „kein Ergebnis“ zurückzukehren, ohne Ausnahme zeigt

Try(x/y).toOption 
+1

Danke. Ihre Antwort ist sehr hilfreich, da sie die möglichen Lösungen erläutert. – Ahmedov

+0

@Ahmedov, danke für das Kompliment. –

1

Sie Teilfunktionen für so etwas wie diese verwenden können.Beispiel:

object MyObject { 
    def main(args: Array[String]) { 

     println(safeDiv.isDefinedAt(1.0, 1.0)) // true 
     println(safeDiv.isDefinedAt(1.0, 0.0)) // false 
     println(safeDiv(1.0, 1.0))    // 1.0 
     println(safeDiv(1.0, 0.0))    // crash 

    } 

    def safeDiv: PartialFunction[(Double, Double), Double] = { 
     case(a,b) if b != 0.0 => a/b 

    } 
} 

Mit Teilfunktionen können Sie überprüfen, ob die Funktion für einen bestimmten Eingang definiert ist. Im obigen Beispiel habe ich gesagt, dass die Funktion safeDiv nicht definiert ist, wenn der Divisor 0,0 ist. Daher können Sie überprüfen, ob die Funktion bei der Eingabe ausgeführt wird. Die Überprüfung ist nicht erforderlich, safeDiv(1.0, 0.0) wird jedoch nicht ausgeführt.

Teilfunktionen ist dein Freund gegen etwas wie folgt aus:

scala> (1.0/0.0).toInt 
res22: Int = 2147483647 
+0

Großartig. Ich denke, es wird handlich werden – Ahmedov