Функция<std::numeric_limits<T>::max()>возвращает наибольшее конечное значение, которое может быть представлено типом T. Если же такой величины нет, то<T()>возвращается.
Для встроенных типов обычно имеется соответствующее значение MACRO TYPE_MAX, где TYPE - CHAR, INT, FLOAT и т.д.
Другие типы, в том числе те, которые предоставляются типдефом, например<INT64_T_MAX>для<int64_t>, могут обеспечивать макроопределение.
Для удовлетворения ситуаций, когда нет специализации<numeric_limits>(например, из-за того, что точность типа изменяется во время выполнения), упакованные версии этой (и других функций) предоставляются с использованием
#include <boost/math/tools/precision.hpp>
T = boost::math::tools::max_value<T>();
Конечно, они просто используют<std::numeric_limits<T>::max()>, если доступны, но в противном случае «делай что-то разумное».
C++11:<std::numeric_limits<T>::lowest()>является
- Для интегральных типов такая же функция<min()>.
- Для типов с плавающей запятой, как правило, отрицательный<max()>(но зависящий от реализации).
-(std::numeric_limits<double>::max)() == std::numeric_limits<double>::lowest();
Функция<std::numeric_limits<T>::min()>возвращает минимальное конечное значение, которое может быть представлено типом T.
Для встроенных типов обычно имеется соответствующее значение MACRO TYPE_MIN, где TYPE - CHAR, INT, FLOAT и т.д.
Другие типы, в том числе те, которые предоставляются типдефом, например<INT64_T_MIN>для<int64_t>, могут обеспечивать макроопределение.
Для типов с плавающей точкой он более полно определяется какминимальное положительное нормализованное значение.
<std::numeric_limits<T>::denorm_min()>для наименьшей денормализованной величины, предусмотренной
std::numeric_limits<T>::has_denorm == std::denorm_present
Для удовлетворения ситуаций, когда нет специализации<numeric_limits>(например, из-за того, что точность типа изменяется во время выполнения), упакованные версии этой (и других функций) предоставляются с использованием
#include <boost/math/tools/precision.hpp>
T = boost::math::tools::min_value<T>();
Конечно, они просто используют<std::numeric_limits<T>::min()>.
Функция<std::numeric_limits<T>::denorm_min()>возвращает наименьшееденормализованное значение, при условии
std::numeric_limits<T>::has_denorm == std::denorm_present
std::cout.precision(std::numeric_limits<double>::max_digits10);
if (std::numeric_limits<double>::has_denorm == std::denorm_present)
{
  double d = std::numeric_limits<double>::denorm_min();
    std::cout << d << std::endl; 
    int exponent;
    double significand = frexp(d, &exponent);
    std::cout << "exponent = " << std::hex << exponent << std::endl; 
    std::cout << "significand = " << std::hex << significand << std::endl; 
}
else
{
  std::cout << "No denormalization. " << std::endl;
}
Экспонент эффективно уменьшается с -308 до -324 (хотя он остается закодированным как ноль и ведущие нули появляются в значении, тем самым теряя точность до тех пор, пока значение не достигнет нуля).
Функция<std::numeric_limits<T>::round_error()>возвращает максимальную ошибку (в единицахULP), которая может быть вызвана любой базовой арифметической операцией.
round_style == std::round_indeterminate;
Стиль округления неопределим во время компиляции.
Для типов с плавающей точкой, когда округление близко, только половина бита теряется при округлении и<round_error
         ==0.5>. В противоположность этому, когда округление приближается к нулю или плюс/минус бесконечности, мы можем освободить до одного бита от округления и<round_error
         ==1>.
Для целых типов округление всегда равно нулю, поэтому в худшем случае можно округлить почти один бит, так<round_error
         ==1>.
<round_error()>может использоваться с<std::numeric_limits<T>::epsilon()>для оценки максимальной потенциальной ошибки, вызванной округлением. Для типов с плавающей запятой<round_error()=1/2>половина эпсилона является максимальной потенциальной ошибкой.
double round_err = std::numeric_limits<double>::epsilon() 
                 * std::numeric_limits<double>::round_error(); 
std::cout << round_err << std::endl; 
Конечно, есть много случаев, когда происходит гораздо большая потеря точности, например, вызванная. Потеря значимости или ошибка отменыили очень много итераций.
Функция<std::numeric_limits<T>::epsilon()>имеет значение только для неинтегральных типов.
Он возвращает разницу между<1.0>и следующим значением, представляемым типом T с плавающей точкой. Таким образом, это одно наименьшее изменение бита в этом значении с плавающей точкой.
Для<double><float_64t><2.2204460492503131e-016>он показывает все, возможно, значительные 17 десятичных знаков.
std::cout.precision(std::numeric_limits<double>::max_digits10);
double d = 1.;
double eps = std::numeric_limits<double>::epsilon();
double dpeps = d+eps;
std::cout << std::showpoint 
  << d << "\n"           
  << dpeps << std::endl; 
std::cout << dpeps - d   
  << std::endl;
Мы можем явно увеличить на один бит, используя функцию<boost::math::float_next()>, и результат такой же, как добавление<epsilon>.
double one = 1.;
double nad = boost::math::float_next(one);
std::cout << nad << "\n"  
  << nad - one 
  << std::endl;
Добавление любого меньшего значения, такого как половина<epsilon>, не повлияет на это значение.
std::cout.precision(std::numeric_limits<double>::max_digits10);
double d = 1.;
double eps = std::numeric_limits<double>::epsilon();
double dpeps = d + eps/2;
std::cout << std::showpoint 
  << dpeps << "\n"       
  << eps/2 << std::endl; 
std::cout << dpeps - d   
  << std::endl;
Таким образом, эта ошибка отмены оставляет значения равными, несмотря на добавление половины<epsilon>.
Для достижения большей переносимости по платформе и типу с плавающей запятой Boost. Математика и рост. Multiprecion предоставляет пакет функций, которые «делают что-то разумное», если стандарт<numeric_limits>недоступен. Используйте их<#include
         <boost/math/tools/precision.hpp>>.
Допуск может быть определен с использованием этой версии эпсилона таким образом:
RealType tolerance = boost::math::tools::epsilon<RealType>() * 2;
<epsilon>очень полезно вычислить допуск при сравнении значений с плавающей точкой, что гораздо более сложная задача, чем принято считать.
Для получения дополнительной информации вы, вероятно, хотите (но все еще нуждаетесь) см.Что должен знать каждый компьютерный ученый об арифметике с плавающей точкой
Наивный тест сравнения абсолютной разницы между двумя значениями и допуском не дает полезных результатов, если значения слишком велики или слишком малы.
Так поднимись. Тест использует алгоритм, впервые разработанный Кнутом для надежной проверки того, достаточно ли близки значения с плавающей точкой.
Увидимся, Дональд. Э. Кнут. Искусство компьютерного программирования (vol II). Copyright 1998 Addison-Wesley Longman, Inc., 0-201-89684-2. Addison-Wesley Professional; 3-е издание.
Смотрите также:
Альберто Сквассия, Сравнение поплавков
Альберто Сквассия, Сравнение поплавкового кода
Сравнение с плавающей точкой.
Например, если мы хотим получить допуск, который мог бы соответствовать примерно 9 арифметическим операциям, скажем sqrt(9) = 3, мы могли бы определить:
T tolerance =  3 * std::numeric_limits<T>::epsilon();
Это очень широко используется в Boost. Тестирование с помощью Boost. Тестовый макрос<BOOST_CHECK_CLOSE_FRACTION>
T expected = 1.0;
T calculated = 1.0 + std::numeric_limits<T>::epsilon();
BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
Используется таким образом:
BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
(Существует также версия, использующая допуск в процентах, а не в долях).
using boost::multiprecision::number;
using boost::multiprecision::cpp_dec_float;
using boost::multiprecision::et_off;
typedef number<cpp_dec_float<50>, et_off > cpp_dec_float_50; 
| ![[Note]](/img/note.png) | Note | 
| Этот буст. Тест еще не позволяет сравнивать с шаблонами экспрессии с плавающей точкой, поэтому параметр шаблона экспрессии по умолчанию был заменен<et_off>. | 
cpp_dec_float_50 tolerance =  3 * std::numeric_limits<cpp_dec_float_50>::epsilon();
cpp_dec_float_50 expected = boost::math::constants::two_pi<cpp_dec_float_50>();
cpp_dec_float_50 calculated = 2 * boost::math::constants::pi<cpp_dec_float_50>();
BOOST_CHECK_CLOSE_FRACTION(expected, calculated, tolerance);
Только для типов с плавающей запятой, для которых<std::numeric_limits<T>::has_infinity
         ==true>, функция<std::numeric_limits<T>::infinity()>обеспечивает определяемое реализацией представление для ∞.
«Представление» — это особый битовый шаблон, зарезервированный для бесконечности. Для системы IEEE754 (для которой<std::numeric_limits<T>::is_iec559
         ==true>)положительная и отрицательная бесконечностьназначаются битовые узоры для всех заданных типов с плавающей запятой.
Смущает то, что строка, возникающая в результате вывода этого представления, также определяется реализацией. И строка, которая может быть введена для создания представления, также определяется реализацией.
Например, выход<1.#INF>на системах Microsoft, но<inf>на большинстве *nix платформ.
Эта реализация-определённость затрудняет использование бесконечности (и NaNs), но усиливается. Математика и рост. Многоточность работы позволяет обеспечить разумное представление длявсехтипов с плавающей запятой, а не только встроенных типов, которые с использованием подходящих граней для определения входных и выходных строк позволяют использовать эти полезные функции переносимо и включая Boost.Serialization.
Для типов с плавающей запятой, для которых<std::numeric_limits<T>::has_quiet_NaN
         ==true>, функция<std::numeric_limits<T>::quiet_NaN()>обеспечивает заданное реализацией представление для NaN.
NaN— значения, указывающие на то, что результат назначения или вычисления бессмыслен. Типичный пример<0/0>, но есть много других.
Для представления отсутствующих значений могут также использоваться NaN: например, они могут, по условности, игнорироваться при расчетах статистики как средства.
Многие проблемы с представлением дляNot-A-Numberзатрудняют портативное использование, подобно тем, которые имеют бесконечность.
NaN может использоваться с бинарными типами многоточности, такими как<cpp_bin_float_quad>:
using boost::multiprecision::cpp_bin_float_quad;
if (std::numeric_limits<cpp_bin_float_quad>::has_quiet_NaN == true)
{
  cpp_bin_float_quad tolerance =  3 * std::numeric_limits<cpp_bin_float_quad>::epsilon();
  cpp_bin_float_quad NaN =  std::numeric_limits<cpp_bin_float_quad>::quiet_NaN();
  std::cout << "cpp_bin_float_quad NaN is "  << NaN << std::endl; 
  cpp_bin_float_quad expected = NaN;
  cpp_bin_float_quad calculated = 2 * NaN;
  
  bool b = expected == calculated;
  std::cout << b << std::endl;
  BOOST_CHECK_NE(expected, expected);
  BOOST_CHECK_NE(expected, calculated);
}
else
{
  std::cout << "Type " << typeid(cpp_bin_float_quad).name() << " does not have NaNs!" << std::endl;
}
Но с помощью Boost. Математика и подходящие грани могут позволить портативное использование как NaN, так и положительной и отрицательной бесконечности.
См.boost:/libs/math/example/nonfinite_facet_sstream.cpp
#include <boost/math/special_functions/nonfinite_num_facets.hpp>
Тогда мы также можем использовать многоточный тип cpp_bin_float_quad:
using boost::multiprecision::cpp_bin_float_quad;
typedef cpp_bin_float_quad T;
using boost::math::nonfinite_num_put;
using boost::math::nonfinite_num_get;
{
  std::locale old_locale;
  std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
  std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
  std::stringstream ss;
  ss.imbue(new_locale);
  T inf = std::numeric_limits<T>::infinity();
  ss << inf; 
  assert(ss.str() == "inf");
  T r;
  ss >> r; 
  assert(inf == r); 
  std::cout << "infinity output was " << ss.str() << std::endl;
  std::cout << "infinity input was " << r << std::endl;
}
infinity output was inf
infinity input was inf
Точно так же мы можем сделать то же самое с NaN (кроме того, что мы не можем использовать<assert>).
{
  std::locale old_locale;
  std::locale tmp_locale(old_locale, new nonfinite_num_put<char>);
  std::locale new_locale(tmp_locale, new nonfinite_num_get<char>);
  std::stringstream ss;
  ss.imbue(new_locale);
  T n;
  T NaN = std::numeric_limits<T>::quiet_NaN();
  ss << NaN; 
  assert(ss.str() == "nan");
  std::cout << "NaN output was " << ss.str() << std::endl;
  ss >> n; 
  std::cout << "NaN input was " << n << std::endl;
}
NaN вход был NaN вход был Nan
Только для типов с плавающей запятой, для которых<std::numeric_limits<T>::has_signaling_NaN
         ==true>, функция<std::numeric_limits<T>::signaling_NaN()>обеспечивает заданное реализацией представление для NaN, которое вызывает аппаратную ловушку. Следует отметить, однако, что по меньшей мере одна реализация этой функции вызывает аппаратную ловушку, которая вызывается просто вызовом<std::numeric_limits<T>::signaling_NaN()>, а не только использованием возвращаемого значения.