Ведет ли инфа C++ std точно так же, как бессмысленная бесконечность

Я реализовывал довольно сложный численный алгоритм. Он содержит некоторые экспоненты, среди которых я обнаружил, после печати промежуточного результата, что были некоторые переполнения double. Тем не менее, терминал печатает inf (не Inf или же NaN), и кажется, что это не двойной, даже не минимальный или максимальный выражаемый двойной. Но похоже inf ведет себя так, как если бы это была расширенная система действительных чисел (точка зрения, что положительная и отрицательная бесконечность должны рассматриваться как истинное число, а не как аббревиатура с ограничениями).

Я провел тест: (версия g++: "Apple LLVM версия 8.0.0 (clang-800.0.42.1)")

#include <iostream> // cout
#include <cmath> // exp, log
#include <limits> // data ranges

int main(void)
{
   const double dMin =std::numeric_limits<int>::min();
   const double dMax =std::numeric_limits<int>::max();
   double p1 =std::exp(710);
   double p2 =std::exp(750);
   double p3 =std::exp(800);
   double p4 =-std::log(0.0);
   std::cout << "p1 :=std::exp(710) =" << p1 << '\n';
   std::cout << "p2 :=std::exp(750) =" << p2 << '\n';
   std::cout << "p3 :=std::exp(800) =" << p3 << '\n';
   std::cout << "p4 :=-std::log(0.0) =" << p4 << '\n';
   std::cout << "does p1==dMax? " << ( (p1==dMax) ? "yes" : "no" ) << '\n';
   std::cout << "does p1==-dMin? " << ( (p1==-dMin) ? "yes" : "no" ) << '\n';
   std::cout << "does p1==p2? " << ( (p1==p2) ? "yes" : "no" ) << '\n';
   std::cout << "does p2==p3? " << ( (p2==p3) ? "yes" : "no" ) << '\n';
   std::cout << "does p3==p4? " << ( (p3==p4) ? "yes" : "no" ) << '\n';
   std::cout << "does 3*p1==p2/2+1? " << ( (3*p1==p2/2+1) ? "yes" : "no" ) << '\n';
   std::cout << "does (-p1)*(-p2)==p3*p3*p3? " << ( ((-p1)*(-p2)==p3*p3*p3) ? "yes" : "no" ) << '\n';
   std::cout << "does std::log(p2)==std::exp(p3)? " << ( (std::log(p2)==std::exp(p3)) ? "yes" : "no" ) << '\n';
}

Выход:

p1 :=std::exp(710) =inf
p2 :=std::exp(750) =inf
p3 :=std::exp(800) =inf
p4 :=-std::log(0.0) =inf
does p1==dMax? no
does p1==-dMin? no
does p1==p2? yes
does p2==p3? yes
does p3==p4? yes
does 3*p1==p2/2+1? yes
does (-p1)*(-p2)==p3*p3*p3? yes
does std::log(p2)==std::exp(p3)? yes

Кажется, что inf действительно напоминает нашу концепцию бесконечности, но не равно максимальному и минимальному стандарту.

Можно ли предположить, что inf работает так же, как бессмысленная бесконечность? Могу ли я положиться на операции на промежуточных этапах моего алгоритма, который включает в себя inf, принимая это за истинную бесконечность, и в конце концов разберитесь с ее результатами? Или если нет, я должен поймать это? Но как я могу, так как это не максимальный или минимальный двойной?

3 ответа

Решение

Как уже упоминалось в других ответах, поведение чисел с плавающей запятой не очень хорошо определено стандартом, однако оно довольно хорошо определено в IEC-559 / IEEE-754, и большинство реализаций используют это. Первое, что нужно сделать, это проверить, эффективно ли это использует ваша реализация:

static_assert(std::numeric_limits<double>::is_iec559, "Stupid implementation!");

Как только вы подтвердите это утверждение, все станет намного проще! Во-первых, вы можете использовать следующую служебную функцию для получения истинной бесконечности (вам не нужно is_iec559 чтобы быть правдой, чтобы это работало на самом деле...)

std::numeric_limits<double>::infinity()

Более того, IEEE-754 имеет очень четко определенные правила поведения бесконечности: http://steve.hollasch.net/cgindex/coding/ieeefloat.html1, например -inf * -inf = +inf, +inf + +inf = +Inf, и так далее. Стандартные математические функции также имеют четко определенное поведение с бесконечностью, поэтому вы также можете на них положиться.

Поэтому, если ваша реализация соответствует стандарту IEEE, да, вы можете положиться на промежуточные операции на бесконечности и проверять только конечные результаты.


1 Это не официальный ресурс, но насколько я знаю, это правильно.

Ограничение этого ответа для IEEE754 с плавающей запятой, +Inf возникает в результате вычислений, подобных 1.0 / 0.0и -Inf возникает из чего-то вроде -1.0 / 0.0,

Другой тип, NaN (не число) возникает из 0.0 / 0.0,

Две переменные с плавающей точкой установлены в +Inf будет сравнивать true друг с другом, то же самое -Inf, Они представляют разные величины для std::numeric_limits<double>::max(), +Inf больше, чем все значения, кроме себя и NaN,

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

(Для чего это стоит, std::log(0.0) должен вернуться -Inf, скорее, чем NaN). См. http://en.cppreference.com/w/cpp/numeric/math/log

Есть ли в C++ стандартная инф...

Стандарт C++ не устанавливает каких-либо требований к поведению бесконечности - или что бесконечность может быть представлена ​​числами с плавающей запятой.

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

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

В самом деле. numeric_limits::max() определяется для возврата максимального конечного значения.

как [ поймать бесконечность], так как это не максимальный или минимальный дубль?

Если под уловом вы подразумеваете, что хотите проверить, является ли значение бесконечностью, вы можете сравнить с numeric_limits::infinity()или, если у вас есть C++11, то std::isinf() (который проверяет как положительную, так и отрицательную бесконечность).

Другие вопросы по тегам