#cpp #c #float
Как определить допустимое значение переменной типа float, используемой в качестве делителя, чтобы избежать ошибки деления на ноль? Достаточно ли сравнить с нулем? float f; //... if (f != 0.f) 1.f / f; Здесь похожий вопрос, где VladD ссылается на IEEE-754, где гарантируется: Если v > 0 и h == 0, то v/h == INFINITY Если v < 0 и h == 0, то v/h == -INFINITY Что в принципе позволит исключить проверку на ноль перед делением, но с другой стороны, стандарт 6.5.5.5 говорит: The result of the / operator is the quotient from the division of the first operand by the second; the result of the % operator is the remainder. In both operations, if the value of the second operand is zero, the behavior is undefined. Вопрос в том, безопасно ли делить float с нулями, и если нет, какое должно быть условие проверки, чтобы получить определенный результат.
Ответы
Ответ 1
В первую очередь хочу отметить, что для выяснения правил работы с числами с плавающей точкой в c или c++ нужно проверить значения соответствующих констант. Т.е. стандарты языков не гарантируют обязательности наличия этих правил, но имеется возможность узнать поддерживает ли та или иная реализация, например, стандарт IEEE-754 для определенного типа. В приложении F (IEC 60559 floating-point arithmetic) стандарта языка c четко сказано: An implementation that defines __STDC_IEC_559__ shall conform to the specifications in this annex. В c++ можно проверить поддержку IEEE-754 для вещественного типа с помощью такого кода: std::numeric_limits::is_iec559 True if and only if the type adheres to IEC 559 standard. International Electrotechnical Commission standard 559 is the same as IEEE 754. Если поддержка обеспечивается, то дальнейшее исследование вопроса нужно производить уже по упомянутому стандарту. Но как показывает практика, ошибка деления на ноль возникает исключительно при делении на ноль, хотя получить бесконечность можно и при делении на отличное от нуля значение: #include #include #include int main() { std::feclearexcept(FE_ALL_EXCEPT); float min = std::numeric_limits ::min(); volatile float zero = 0.0f; std::cout << 10.f / min << '\n'; if(std::fetestexcept(FE_DIVBYZERO)) { std::cout << "division by zero reported\n"; } else { std::cout << "division by zero not reported\n"; } } Получим: inf division by zero not reported Если заменим min на zero, то уже: inf division by zero reported Поэтому для себя надо решить, чего же действительно хочется избежать: ошибки деления на ноль или получения бесконечности. Согласно IEEE-754 п.7.3 исключение типа "деление на ноль" возникает только при действиях на конечных операндах в двух случаях: деление ненулевого значения на ноль; вычисление логарифма от нуля. Ответ 2
Я подозреваю, что Стандарт языка должен опираться на IEEE-754 в вопросах плавающей арифметики, а всё остальное касается только целых чисел. В Стандарте IEEE-754 сказано, что ненулевое значение (в том числе бесконечность) может быть поделено на ноль, результатом будет бесконечность. Деление нуля на ноль тоже допустимо, при этом получим quite NaN, то есть аналог некоей неопределённости. Согласитесь, было бы странно, что если процессор работает строго по IEEE-754, а компилятор языка - нет. Далее, если опасаться того, что результат может стать бесконечным, то знаменатель вовсе не обязан быть равным нулю, он может быть, например, равен 0,5, а числитель чуть больше половины максимально возможного значения. Получается, что для избежании бесконечного ответа, явно недостаточно проверять знаменатель на 0.0f, нужно заведомо соотнести знаменатель с числителем, а сделать это можно через деление, перед которым, собственно, мы и пытаемся сделать проверку : ) Сомневаюсь, что создатели языка настолько недальновидны, что допустили бы такой промах.
Комментариев нет:
Отправить комментарий