Inconsistencia en comportamiento dividido por cero entre diferentes tipos de valores

Por favor considere el siguiente código y comentarios:

Console.WriteLine(1 / 0); // will not compile, error: Division by constant zero int i = 0; Console.WriteLine(1 / i); // compiles, runs, throws: DivideByZeroException double d = 0; Console.WriteLine(1 / d); // compiles, runs, results in: Infinity 

Puedo entender que el comstackdor compruebe activamente la división por constante cero y la DivideByZeroException en tiempo de ejecución pero:

¿Por qué usar un doble en un retorno de divide por cero Infinito en lugar de arrojar una excepción? ¿Es esto por diseño o es un error?

Solo por las patadas, hice esto en VB.NET también, con resultados “más consistentes”:

 dim d as double = 0.0 Console.WriteLine(1 / d) ' compiles, runs, results in: Infinity dim i as Integer = 0 Console.WriteLine(1 / i) ' compiles, runs, results in: Infinity Console.WriteLine(1 / 0) ' compiles, runs, results in: Infinity 

EDITAR:

Basado en los comentarios de kekekela ejecuté lo siguiente que resultó en infinito:

  Console.WriteLine(1 / .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001); 

Esta prueba parece corroborar la idea y un doble literal de 0.0 es en realidad una fracción muy, muy pequeña que dará como resultado Infinito …

En pocas palabras: el tipo double define un valor para infinito, mientras que el tipo int no lo hace. Entonces, en el caso double , el resultado del cálculo es un valor que se puede express en el tipo dado desde que se definió. En el caso int , no hay ningún valor para infinito y, por lo tanto, no hay manera de devolver un resultado preciso. De ahí la excepción.

VB.NET hace las cosas un poco diferente; la división entera da como resultado automáticamente un valor de coma flotante usando el operador / . Esto es para permitir a los desarrolladores escribir, por ejemplo, la expresión 1 / 2 , y hacer que evalúe a 0.5 , lo que algunos considerarían intuitivo. Si desea ver un comportamiento consistente con C #, intente esto:

 Console.WriteLine(1 \ 0) 

Tenga en cuenta el uso del operador de división de enteros ( \ , not / ) de arriba. Creo que obtendrás una excepción (o un error de comstackción, no estoy seguro de cuál).

Del mismo modo, intenta esto:

 Dim x As Object = 1 / 0 Console.WriteLine(x.GetType()) 

El código anterior arrojará System.Double .

En cuanto al punto acerca de la imprecisión, aquí hay otra forma de verlo. No es que el tipo double no tenga ningún valor exactamente cero (lo hace); más bien, el tipo double no está destinado a proporcionar resultados matemáticamente exactos en primer lugar. (Ciertos valores pueden representarse exactamente, sí. Pero los cálculos no dan ninguna promesa de precisión.) Después de todo, el valor de la expresión matemática 1/0 no está definido (último controlé). Pero 1 / x acerca al infinito cuando x se aproxima a cero. Entonces, desde esta perspectiva, si no podemos representar la mayoría de las fracciones n / m exactamente de todos modos, tiene sentido tratar el caso x / 0 como aproximado y dar el valor al que se acerca; una vez más , se define al infinito, al menos.

Un doble es un número de coma flotante y no un valor exacto, por lo que lo que realmente está dividiendo desde el punto de vista del comstackdor es algo cercano a cero, pero no exactamente cero.

Porque el punto flotante “numérico” no es nada de eso. Operaciones de punto flotante:

  • no son asociativos
  • no son distributivos
  • puede no tener un inverso multiplicativo

(ver http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-point.pdf para algunos ejemplos)

El punto flotante es una construcción para resolver un problema específico, y se usa cuando no debería. Creo que son bastante horribles, pero eso es subjetivo.

Esto probablemente tiene algo que ver con el hecho de que los números de coma flotante de doble punto y coma flotante estándar IEEE tienen un valor de “infinito” especificado. .NET solo está exponiendo algo que ya existe, a nivel de hardware.

Vea la respuesta de kekekela para saber por qué esto tiene sentido, lógicamente.

Esto es por diseño porque el tipo double cumple con IEEE 754 , el estándar para la aritmética de coma flotante. Consulte la documentación de Double.NegativeInfinity y Double.PositiveInfinity .

El valor de esta constante es el resultado de dividir un número positivo (o negativo) por cero.