Почему деление на ноль с числами с плавающей запятой (или двойной точностью) не генерирует java.lang.ArithmeticException: / в ноль в Java

Следующее заявление бросает java.lang.ArithmeticException: / by zero как очевидно.

System.out.println(0/0);

потому что буквальный 0 считается int Литерал и деление на ноль не допускаются в целочисленной арифметике.

Однако в следующем случае исключение не выдается java.lang.ArithmeticException: / by zero,

int a = 0;
double b = 6.199;
System.out.println((b/a));

Отображает Infinity,

Следующее утверждение производит NaN (Не число) без исключения.

System.out.println(0D/0); //or 0.0/0, or 0.0/0.0 or 0/0.0 - floating point arithmetic.

В этом случае оба операнда считаются двойными.


Точно так же следующие операторы не выдают никаких исключений.

double div1 = 0D/0; //or 0D/0D
double div2 = 0/0D; //or 0D/0D

System.out.printf("div1 = %s : div2 = %s%n", div1, div2);
System.out.printf("div1 == div2 : %b%n", div1 == div2);
System.out.printf("div1 == div1 : %b%n", div1 == div1);
System.out.printf("div2 == div2 : %b%n", div2 == div2);
System.out.printf("Double.NaN == Double.NaN : %b%n", Double.NaN == Double.NaN);
System.out.printf("Float.NaN == Float.NaN : %b%n", Float.NaN == Float.NaN);

Они производят следующий вывод.

div1 = NaN : div2 = NaN
div1 == div2 : false
div1 == div1 : false
div2 == div2 : false
Double.NaN == Double.NaN : false
Float.NaN == Float.NaN : false

Они все возвращаются false. Почему эта операция (деление на ноль) допускается с числами с плавающей запятой или с двойной точностью?


Кстати, я могу понять, что числа с плавающей запятой (числа с двойной точностью) имеют свои значения, которые представляют собой положительную бесконечность, отрицательную бесконечность, а не число (NaN)...

6 ответов

Решение

Короче говоря, именно так это указано в стандарте IEEE-754, на котором основаны операции Java с плавающей запятой.

Почему деление на ноль (или переполнение, или переполнение) не останавливает программу и не вызывает ошибку? Почему стандарт на числа включает "не число" (NaN)?

Модель 754 поддерживает надежные программы. Он предназначен не только для числовых аналитиков, но и для пользователей электронных таблиц, систем баз данных или даже кофейников. Правила распространения для NaN и бесконечностей допускают исчезновение несущественных исключений. Точно так же постепенное снижение поддерживает свойства ошибки в диапазоне точности.

Когда исключительные ситуации требуют внимания, они могут быть рассмотрены немедленно через ловушки или в удобное время с помощью флагов состояния. Ловушки могут быть использованы для остановки программы, но неисправимые ситуации встречаются крайне редко. Простая остановка программы не подходит для встроенных систем или сетевых агентов. Чаще всего ловушки регистрируют диагностическую информацию или заменяют действительные результаты.

Флаги предлагают как предсказуемый поток управления, так и скорость. Их использование требует, чтобы программист знал об исключительных условиях, но пометка флага позволяет программистам откладывать обработку исключительных условий до тех пор, пока это не будет необходимо.

Это так, потому что так определил IEEE 754.

Деление на число с плавающей запятой 0.0 дает NaN или +/-Inf, в зависимости от того, является ли числитель 0 или нет.

Деление на целое число 0 не охватывается IEEE 754 и создает исключение - нет другого способа указать ошибку, потому что int не может представлять NaN или же Inf,

Генерация исключения аналогична (программное обеспечение) INT генерируется делением на ноль на микропроцессорах x86.

Бесконечность не предел

class DoubleDivision {

    public static void main(String[] args) {
        System.out.println(5.0/0.0);
    }
}

Код выше и фрагменты, которые вы упомянули, дают infinity,

Почему Java использует Double s для представления десятичных дробей. Двоичный код не может полностью представлять число, он может представлять только приближение и, следовательно, также не может быть двойным в Java.

Представьте число, невероятно близкое к нулю. Если вы знаете исчисление, представьте предел в ноль. Переменная будет приближаться к нулю до некоторого минимально возможного расстояния, но никогда не будет точно равна. Вы можете себе это представить, верно? Ну, предположим, что для представления числа нужно столько точности, что оно сдается и вызывает его 0.0 потому что у него нет хорошей альтернативы. Вот что здесь происходит. Любое регулярное число, деленное на супер близкое к нулю число, в основном, бесконечность. Попытайся: 5 / (10^-100),

Также обратитесь к разделу: Специальные значения с плавающей точкой в математических ошибках для получения дополнительной информации:)

Смежный вопрос: почему 1/0 дает ошибку, а 1.0/0/0 дает инфу

ОБНОВИТЬ: INT не имеет бесконечности и NaN значение в наборе, тогда как поплавок имеет бесконечность и NaN значение. (В соответствии со стандартами IEEE 754, которым следует Java)

Когда есть деление на ноль, компьютер не может создать представление результата в виде числа. Компьютер должен сигнализировать, что результатом является не число.

Для значений с плавающей запятой он может выдавать специальное не-числовое значение для стража, потому что есть некоторые 32-битные (для float) и 64-битный (для double) битовые комбинации, которые не представляют число и, следовательно, могут быть интерпретированы как не число (NaN).

Для целочисленных значений, использующих общую схему с двойным дополнением (как того требует Java), все 32-разрядные (для int) и 64-битный (для long) битовые комбинации представляют число. Таким образом, компьютер не может сообщить о проблеме с помощью дозорного. Он должен сообщить о проблеме "вне группы" каким-то образом. Исключение - это внеполосный метод, выбранный для Java.

Java следует стандарту IEEE 754, который определяет значения, возвращаемые по умолчанию в случае деления на ноль. http://en.wikipedia.org/wiki/IEEE_754

Деление на ноль (операция с конечными операндами дает точный бесконечный результат, например, 1/0 или log(0)) (возвращает ± бесконечность по умолчанию).

import java.util.Scanner;

public class Division {

    public static void main(String[] args) {
        int a, b;
        float result;

        Scanner input = new Scanner(System.in);
        System.out.println("Enter value for a : ");
        a = input.nextInt();

        System.out.println("Enter value for b : ");
        b = input.nextInt();

        try {
            /* here we used "if clause" because result will be in float
             note: Here result is in float, so JVM Cant Catch Exception.
             if we Try to Divide with Zero with Float Values It gives Output as
             Divided by Zero is Infinity */
            if (b != 0) {
                result = (float) a / b;
                System.out.println("Result of " + a + " divided by " + b + " is : " + result);
            } else // here result will be in integer so Jvm can easily Catch The Exception
            {
                result = a / b;
            }
        } catch (ArithmeticException e) {
            System.out.println("Sorry Division By Zero Is Not Possible");
        }
    }
}

/* Ouput :
Enter value for a :2
Enter value for b : 7
Result of 2 divided by 7 is : 0.2857143 */

 /* Ouput :
Enter value for a : 16
Enter value for b : 0
Sorry Division By Zero Is Not Possible */
Другие вопросы по тегам