Подтвердить что ты не робот

Несогласованность в поведении по принципу "один за другим" между разными типами значений

Пожалуйста, рассмотрите следующий код и комментарии:

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   

Я могу понять, что компилятор активно проверяет деление на нулевую константу и DivideByZeroException во время выполнения, но:

Почему использование двойного в делении на ноль возвращает бесконечность, а не генерирует исключение? Это по замыслу или это ошибка?

Просто для удовольствия, я сделал это и в VB.NET, получив "более согласованные" результаты:

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

РЕДАКТИРОВАТЬ:

Основываясь на отзывах Кекекела, я запустил следующее, что привело к бесконечности:

Console.WriteLine(1 / .0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001);

Этот тест, кажется, подтверждает идею, и буквальное двойное число 0.0 на самом деле очень, очень крошечная дробь, которая приведет к бесконечности...

4b9b3361

Ответ 1

В двух словах: тип double определяет значение бесконечности, а тип int - нет. Таким образом, в случае double результат вычисления - это значение, которое вы действительно можете выразить в заданном типе, поскольку оно определено. В случае int для бесконечности нет значения и, следовательно, нет способа вернуть точный результат. Отсюда исключение.

VB.NET делает вещи немного по-другому; целочисленное деление автоматически приводит к значению с плавающей запятой, используя оператор /. Это позволяет разработчикам писать, например, выражение 1 / 2, и оценивать его до 0.5, что некоторые считают интуитивным. Если вы хотите увидеть поведение, совместимое с С#, попробуйте следующее:

Console.WriteLine(1 \ 0)

Обратите внимание на использование оператора целочисленного деления (\, not /) выше. Я считаю, что вы получите исключение (или ошибку компиляции - не знаете, какой).

Аналогично попробуйте следующее:

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

Вышеприведенный код выводит System.Double.

Что касается точки неточности, то здесь еще один способ взглянуть на нее. Дело не в том, что тип double не имеет значения для ровно нуля (он делает); скорее, тип double не предназначен для обеспечения математически точных результатов в первую очередь. (Определенные значения могут быть представлены точно, да, но расчеты не дают обещания точности.) В конце концов, значение математического выражения 1 / 0 не определено (последнее я проверил). Но 1 / x стремится к бесконечности при приближении x к нулю. Итак, с этой точки зрения, если мы вообще не можем представлять большинство дробей n / m, имеет смысл рассматривать случай x / 0 как приблизительный и давать значение, по которому оно приближается - опять же, бесконечность определяется, по крайней мере.

Ответ 2

Двойной номер числа с плавающей запятой, а не точное значение, поэтому то, что вы действительно разделяете с точки зрения компилятора, приближается к нулю, но не точно равно нулю.

Ответ 3

Потому что "числовая" плавающая точка не имеет ничего подобного. Операции с плавающей запятой:

  • не являются ассоциативными
  • не являются дистрибутивными
  • может не иметь мультипликативного обратного

(см. http://www.cs.uiuc.edu/class/fa07/cs498mjg/notes/floating-point.pdf для некоторых примеров)

Плавающая точка - это конструкция для решения конкретной проблемы и используется повсюду, когда ее не должно быть. Я думаю, что они довольно ужасные, но это субъективно.

Ответ 4

Вероятно, это связано с тем, что стандартные числа с плавающей запятой с плавающей точкой и двойной точностью IEEE имеют заданное значение "бесконечность"..NET просто раскрывает то, что уже существует, на аппаратном уровне.

См. kekekela ответ, почему это имеет смысл, логически.

Ответ 5

Это по дизайну, потому что тип double соответствует IEEE 754, стандарту для арифметики с плавающей запятой. Ознакомьтесь с документацией для Double.NegativeInfinity и Double.PositiveInfinity.

Значение этой константы является результатом деления положительного (или отрицательного) числа на ноль.