Ведет ли инфа 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()
(который проверяет как положительную, так и отрицательную бесконечность).