Divide Underflow - PullRequest
       42

Divide Underflow

2 голосов
/ 13 января 2012

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

1 Ответ

3 голосов
/ 13 января 2012

С http://www.strw.leidenuniv.nl/docs/intel/f_ug/ieee_ovw.htm

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

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

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

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

Пример

В C # эпсилон равен 1,401298E-45.

эпсилон / эпсилон == 1,0f

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

Теперь, если вы попробуете что-то вроде этого:

float max = 3.40282347E+38f;

/// underflow, denominator will be 0.0f
float denominator = epsilon / max; 

denominator будет иметь порядок 1e-83. Поскольку 83 намного превышает максимальный показатель с плавающей запятой одинарной точности, значение будет ограничено до нуля. Это место, где происходит недостаточное заполнение.

/// generates a divide-by-zero error.
float result = 10 / denominator; 

Это генерирует деление на ноль вместо бесконечности, потому что промежуточный результат, сохраненный в denominator, сначала фиксируется на 0 перед использованием во второй операции.

Независимо от того, получаете ли вы недополнение или деление на ноль, зависит от компилятора, вашего использования и порядка скобок и т. Д.

Например, снова в C #:

10f / float.Epsilon / float.MaxValue

а также

(10f / float.Epsilon) / float.MaxValue

дает 20971522.0f.

Тем не менее, математически эквивалентное выражение:

10f / (float.Epsilon / float.MaxValue)

дает Бесконечность.

...