Scala division by zero yields different results
Asked Answered
E

3

11

I am confused with how Scala handles division by zero. Here is a REPL code snippet.

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

As you can see in the above example, depending on how you divide by zero, you get one of the following:

  • "java.lang.ArithmeticException: / by zero"
  • "Double = NaN"
  • "Double = Infinity"

This makes debugging quite challenging especially when dealing with data of unknown characteristics. What is the reasoning behind this approach, or even a better question, how to handle division by zero in a unified manner in Scala?

Evaluate answered 12/5, 2017 at 13:0 Comment(3)
I think this has to do with the different datatypes. When performing different, yet related, calculations, try to always use the same datatypes. Eg.: Double, Int, etcBirkenhead
You may be dealing with data of unknown characteristics, but in a statically typed language like Scala you aren't dealing with data of unknown type.Manriquez
@AlexeyRomanov I do understand what you mean. However, I guess most people would agree that this kind of approach is prone to some very dirty bugs as well as being very tedious to handle in every piece of arithmetic operation you write.Evaluate
E
22

It's all down to the division by zero rules for various types.

0 / 0 is an integer division by zero (as both arguments are integer literals), and that is required to throw a java.lang.ArithmeticException.

1.toDouble/0.toDouble is a floating point division by zero with a positive numerator, and that is required to evaluate to +Infinity.

0.0/0.0 is a floating point division by zero with a zero numerator, and that is required to evaluate to +NaN.

The first is a Java and Scala convention, the other two are properties of IEEE754 floating point, which is what Java and Scala both use.

Encaenia answered 12/5, 2017 at 13:2 Comment(0)
L
5

Doubles and Floats are floating-point values (more here) which can be represented as +Infinity -Infinity and NaN as defined in IEEE 754 standard.
Integers are fixed numbers which do not have any way of explicitly indicating invalid data, thus they throw exceptions
Unified solution to this would be to use getOrElse method on Try

Try(x/y).getOrElse(0)

In case you want to recover only on ArithmeticException you can use recover and get

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

recover allows you to convert Failure to Success
You can also use Try to Option to return "no result" without showing exception

Try(x/y).toOption
Leenaleeper answered 12/5, 2017 at 16:48 Comment(2)
Thanks. Your answer is quite helpful in that it elaborates on the possible solutions.Evaluate
I have found Try(1.0 / 0.0) will return Success(Infinity) and not Failure and the OrElse isn't be returned.Acting
C
1

You can use partial functions for something like this. For example:

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 

    }   
}

Partial functions allow you to check whether the function is defined for a given input. In the example above, I said the the function safeDiv is not defined if the divisor is 0.0. Therefore you can check if the function will execute given the input. The check is not necessary, however safeDiv(1.0, 0.0) will not execute.

Partial functions is your friend against something like this:

scala> (1.0/0.0).toInt
res22: Int = 2147483647
Comprise answered 13/5, 2017 at 6:29 Comment(1)
Great. I think It will become handyEvaluate

© 2022 - 2024 — McMap. All rights reserved.