Почему потеря значимости при делении возникает только тогда, когда делитель намного меньше делимого, разве это не должно происходить в любое время, когда знаменатель достаточно близок к нулю, независимо от размера дивиденда?
Разделить нижний поток
Ответы (1)
Из 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)
дает Бесконечность.