14

I ran the following snippet in the VS2015 C# interactive and got some very weird behavior.

> double divide(double a, double b)
. {
.     try
.     {
.         return a / b;
.     }
.     catch (DivideByZeroException exception)
.     {
.         throw new ArgumentException("Argument b must be non zero.", exception);
.     }
. }    
> divide(3,0)
Infinity    
> 3 / 0
(1,1): error CS0020: Division by constant zero
> var b = 0;
> 3 / b
Attempted to divide by zero.
> 

Why did the method return infinity while 3 / 0 threw an error and 3 / b threw a formated error? Can I force the division to have thrown an error instead of returning infinity?

If I reformat the method to

double divide(double a, double b)
{
    if ( b == 0 )
    {
        throw new ArgumentException("Argument b must be non zero.", new DivideByZeroException());
    }
    return a / b;
}

would the new DivideByZeroException contain all the same information and structure that the caught exception would?

Kelson Ball
  • 948
  • 1
  • 13
  • 30

4 Answers4

23

It's because you use System.Double.

As stated by MSDN DivideByZeroException is thrown only for integral types and Decimal.

That's because it is hard to define "so called" zero for Double value.

PositiveInfinity also results from a division by zero with a positive dividend, and NegativeInfinity results from a division by zero with a negative dividend. (source: MSDN again)

DivideByZeroException is not appropriate for floating point types. Note: You can get NaN though when attempting to divide by zero with a dividend of zero.

  • 1
    But why are PositiveInfinity, NegativeInfinity or NaN used for doubles, rather than throwing exceptions? This means the code fails silently, with calculations continuing (and those values propagating), and the consequence is that a) the output is likely to be garbage, b) the user may not even be aware that there is a problem (particularly if the code is a background, unattended process on a server), and c) if the problem is detected, it will be tedious tracing it back to its first occurrence in the code (and there may be many places where it could occur). – patrickjlee May 03 '19 at 06:40
  • @patrickjlee you labeled it "failure", but it is not necessarily treated as such. It all depends on the task. IMHO `Single` and `Double` are often misused in business logic implemetation: these types being inexact lead to much bigger problems in my experience, if not treated carefully. – Sergey.quixoticaxis.Ivanov May 03 '19 at 09:19
  • @sergey-quixoticaxis-ivanov I have been writing financial software for more than 30 years and I have never come across a situation where it would be appropriate for the software to continue running after a Infinity, -Infinity or NaN have been generated as the result of a calculation. Such a situation is almost invariably the result of an unexpected situation in the data, or an error in the code, and so the user needs to be alerted that there is a problem. So the current default behaviour (in .NET Core 3.0 and earlier, and .NET 4.72 and earlier) is a nuisance for such applications in my view. – patrickjlee May 11 '19 at 16:29
  • 1
    @patrickjlee I totally like the comments about 30 years of writing financial software. I'm happy for you if you used imprecise floating point types without total ordering for all those years and never shot yourself in the foot. But all financial software I've seen (and I should say that I've seen only the software of trading desks) uses precise types (and is not written in C#). C# has a nice `decimal` type though which is tailored for money related tasks. For the non money related scenarios like scientific computations and 3D modeling of all sorts infinity and NaN are quite common. – Sergey.quixoticaxis.Ivanov Sep 11 '20 at 15:00
2

Why did the method return infinity while 3 / 0 threw an error and 3 / b threw a formated error?

Because in the first case the 0 is not an integer, is a double. While in the second is an integer. That you should realize here is that a double is a floating point number. So it doesn't have an exact value like an integer. On the other hand an integer can be represented by a computer with 100% accuracy.

Here you could find a very nice article regarding floating point numbers.

Christos
  • 53,228
  • 8
  • 76
  • 108
1

As others have stated above, it's due to you using double as the divisor. You can prove it by using your variables example but using double instead of var.

> double a = 3;
> double b = 0;
> a/b
∞
Rich Linnell
  • 973
  • 5
  • 14
  • Thank you for pointing that out, I had forgotten I had used var. Specifying 0 as a double literal evaluated to infinity as well. – Kelson Ball Jul 25 '16 at 20:15
-1

Int in Java is 2's complement. A two's-complement integer doesn't have any bits available to store special values like Infinity or NaN, so since the result is not representable in the desired type, an exception has to be thrown. Floating-point numbers do not have this problem (there is a bit pattern available for Infinity), and therefore no exception is needed.

codemonger
  • 47
  • 8