Может ли деление на ненулевое значение создать нан / бесконечность?

У меня есть число, которое может быть нулями. Я делю на это число, поэтому я хочу проверить, равен ли он нулю, чтобы предотвратить NaN и бесконечности. Возможно ли, что я все еще создаю NaNs / бесконечность из-за ошибок округления внутри деления?

double x; // might be zero
double y;

if(x != 0) return y / x;

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

Спасибо за ответы. Я добавлю несколько подвопросов тогда.

1) предполагая, что ни x, ни y не являются NaN / + inf или -inf, приведет ли деление, которое приводит к -inf / + inf, к увеличению числа циклов ЦП или к любому другому нежелательному поведению? (Может ли это потерпеть крах?)

2) есть ли способ предотвратить разделение на бесконечность? Использование смещений и так далее.

9

Решение

Может ли деление на ненулевое значение создать нан / бесконечность?

Да.

Если соблюдается IEEE-754, то:

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

Правила других представлений могут быть разными.


2) есть ли способ предотвратить отклонение, приводящее к бесконечности

Это должно иметь большое значение для предотвращения этого:

#include <cfenv>
#include <cassert>
#include <cmath>
#include <limits>

// ...

static_assert(std::numeric_limits<decltype(x)>::is_iec559, "Unknown floating point standard.");
#pragma STDC FENV_ACCESS ON
int failed = std::fesetround(FE_TOWARDZERO);
assert(!failed);
if(x != 0 && std::isfinite(x) && std::isfinite(y))
return y / x;
else
throw std::invalid_argument("informative message");

Некоторым компиляторам могут потребоваться параметры не по умолчанию, чтобы включить полное соответствие IEEE 754 (-frounding-math на GCC).

9

Другие решения

Разделение очень маленького числа на очень большое число или умножение двух очень больших чисел может привести к «бесконечности». Разделив бесконечность на другую бесконечность, мы получим NaN. Например, (1E300/1E-300)/(1E300/1E-300) или же (1E300*1E300)/(1E300*1E300) оба принесут NaN.

6

Да, просто посмотрите на код ниже

#include <iostream>
int main ()
{
double x = 1, y = 2;
while (y != 0) {
std::cout << y << " " << x / y << std::endl;
y /= 2;
}
}

в какой-то момент вы получите:

8.9003e-308 1.12356e+307
4.45015e-308 2.24712e+307
2.22507e-308 4.49423e+307
1.11254e-308 8.98847e+307
5.56268e-309 inf
2.78134e-309 inf
1.39067e-309 inf
6.95336e-310 inf
5
По вопросам рекламы [email protected]