C ++ двойное деление на 0,0 против DBL_MIN - PullRequest
2 голосов
/ 25 мая 2010

При нахождении обратного корня квадратного из двойного числа, лучше ли зажимать недопустимые неположительные входные значения при 0,0 или MIN_DBL? (В моем примере ниже double b может оказаться отрицательным из-за ошибок округления с плавающей запятой и из-за того, что законы физики слегка выдуманы в игре.)

Оба деления на 0.0 и MIN_DBL дают одинаковый результат в игре, потому что 1/0.0 и 1/DBL_MIN фактически равны бесконечности. Моя интуиция говорит, что MIN_DBL - лучший выбор, но будет ли какой-либо вариант использования 0.0? Как, например, sqrt(0.0), 1/0.0 и умножение на 1.#INF000000000000 выполняется быстрее, потому что это особые случаи.

double b = 1 - v.length_squared()/(c*c);

#ifdef CLAMP_BY_0
if (b < 0.0) b = 0.0;
#endif

#ifdef CLAMP_BY_DBL_MIN
if (b <= 0.0) b = DBL_MIN;
#endif

double lorentz_factor = 1/sqrt(b);

двойное деление в MSVC:

1/0.0     = 1.#INF000000000000
1/DBL_MIN = 4.4942328371557898e+307

Ответы [ 2 ]

2 голосов
/ 25 мая 2010

При работе с математикой с плавающей запятой "бесконечность" и "фактически бесконечность" совершенно разные. Как только число перестает быть конечным, оно стремится остаться таким. Таким образом, хотя значение lorentz_factor «эффективно» одинаково для обоих методов, в зависимости от того, как вы используете это значение, последующие вычисления могут радикально отличаться. Например, sqrt(lorentz_factor) остается бесконечным, если вы ограничиваете 0, но фактически будет вычисляться, если вы ограничиваете какое-то очень очень маленькое число.

Таким образом, ответ во многом будет зависеть от того, что вы планируете делать с этим значением, как только вы его зафиксировали.

0 голосов
/ 25 мая 2010

Почему бы просто не присвоить INF для lorentz_factor напрямую, избегая как вызова sqrt, так и разделения?

double lorentz_factor;
if (b <= 0.0) 
    lorentz_factor = std::numeric_limits<double>::infinity();
else
    lorentz_factor = 1/sqrt(b);
  • Для этого вам нужно будет #include <limits>.
  • Вы также можете использовать ::max() вместо ::infinity(), если это то, что вам нужно.
...