Карта сайта Kansoftware
НОВОСТИУСЛУГИРЕШЕНИЯКОНТАКТЫ
Разработка программного обеспечения

std::numeric_limits<> constants

Boost , Chapter 1. Boost.Multiprecision , Numeric Limits

Boost C++ Libraries

...one of the most highly regarded and expertly designed C++ library projects in the world. Herb Sutter and Andrei Alexandrescu, C++ Coding Standards

PrevUpHomeNext
is_specialized

<true>для всех типов арифметики (целое число, плавающая и фиксированная точка), для которых<std::numeric_limits<T>::numeric_limits>является специализированным.

Типичным тестом является

if (std::numeric_limits<T>::is_specialized == false)
{
  std::cout << "type " << typeid(T).name()  << " is not specialized for std::numeric_limits!" << std::endl;
// ...
}

Как правило,<numeric_limits<T>::is_specialized>является<true>для всех<T>, где постоянные члены<numeric_limits>времени компиляции действительно известны во время компиляции и не изменяются во время выполнения. Например, типы с плавающей запятой с переменной точностью выполнения, такие как<mpfr_float>, не имеют специализации<numeric_limits>, поскольку невозможно определить всех участников во время компиляции. В отличие от этого, точность типа<mpfr_float_50>известна во время компиляции, и поэтомуимеет специализацию<numeric_limits>.

Обратите внимание, что не все константы и функции<std::numeric_limits>являются значимыми для всех определяемых пользователем типов (UDT), таких как десятичные и двоичные типы многоточности, представленные здесь. Более подробная информация об этом приводится в разделах ниже.

infinity

Для типов с плавающей точкой ∞ определяется везде, где это возможно, но ясно, что бесконечность бессмысленна для __arbitrary_precision arithmetic backends, и есть один тип с плавающей точкой (GMP<mpf_t>, см.gmp_float), который вообще не имеет понятия бесконечности или NaN.

Типичный тест на реализацию бесконечности

if(std::numeric_limits<T>::has_infinity)
{
   std::cout << std::numeric_limits<T>::infinity() << std::endl;
}

Использование подобных тестов настоятельно рекомендуется для улучшения переносимости.

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

is_signed

<std::numeric_limits<T>::is_signed== true>Если подпись<T>.

Для встроенных бинарных типов знак удерживается в одном бите, но для других типов (cpp_dec_float и cpp_bin_float) он может быть отдельным элементом хранения, обычно<bool>.

is_exact

<std::numeric_limits<T>::is_exact== true>Если тип Т использует точные представления.

Это<true>для всех целых типов и<false>для типов с плавающей запятой.

Обсуждается полезное определение.

ISO/IEC 10967-1, Языковая независимая арифметика, отмеченная C++ Стандарт определяет

A floating-point type F shall be a finite subset of [real].

Важное практическое различие заключается в том, что все целые числа (до 26) могут храниться точно.

Рациональныетипы, использующие два целых типа, также точны.

Типы плавающих точекне могут хранить все действительные значения(те, что в наборе ℜ)точно. Например, 0,5 может храниться точно в двоичной плавающей точке, но 0,1 не может. То, что хранится, является ближайшей репрезентативной реальной ценностью, то есть округленной до ближайшей.

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

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

Децимальный ТР.

А такжеC++ Бинарная арифметика с фиксированной точкой.

is_bounded

<std::numeric_limits<T>::is_bounded== true>если набор значений, представленный типом<T>, является конечным.

Это<true>для всех встроенных целочисленных, фиксированных и плавающих типов и для большинства многоточных типов.

Это только<false>для нескольких типов произвольной точности, таких как<cpp_int>.

Рациональные и фиксированные представления являются точными, но не целыми.

is_modulo

<std::numeric_limits<T>::is_modulo>определяется как<true>, если добавление двух положительных значений типа T может дать результат меньше, чем любое из значений.

<is_modulo== true>означает, что тип не переполняется, а, например, «окружается» до нуля, при добавлении одного к значению<max()>.

Для большинства встроенных целочисленных типов<std::numeric_limits<>::is_modulo>составляет<true>.

<bool>Это единственное исключение.

Поведение модуля иногда полезно, но также может быть неожиданным, а иногда и нежелательным.

Переполнение подписанных целых чисел может быть особенно неожиданным, что может привести к изменению знака.

Повышаю. Многоточный целочисленный тип<cpp_int>не является модулем, поскольку в качестве __arbitrary_precision типов он расширяется, чтобы удерживать любое значение, которое позволяют ресурсы машины.

Однако фиксированная точностьcpp_intможет быть модульной, если они не контролируются (то есть они ведут себя так же, как встроенные в целые числа), но не если они проверяются (переток вызывает исключение).

Встроенные и многоточные типы плавающих точек обычно не являются модулем.

По возможности, перелив<std::numeric_limits<>::infinity()>при условии<std::numeric_limits<>::has_infinity ==true>.

radix

Константа<std::numeric_limits<T>::radix>возвращает либо 2 (для встроенных и двоичных типов), либо 10 (для десятичных типов).

digits

Число<radix>цифр, которые представлены без изменения:

  • Для целочисленных типов числонезнаковых битовв значении.
  • Для плавающих типов числорадиксовых цифрв значении.

Значения включают любой неявный бит, так, например, для вездесущего<double>, использующего 64 битаIEEE binary64,<digits>== 53, даже если в представлении есть только 52 действительных бита значащего. Значение<digits>отражает тот факт, что существует один неявный бит, который всегда устанавливается на 1.

Начало. Многоточные двоичные типы не используют неявный бит, поэтому элемент<digits>отражает, сколько именно битов точности было запрошено:

typedef number<cpp_bin_float<53, digit_base_2> >   float64;
typedef number<cpp_bin_float<113, digit_base_2> >  float128;
std::numeric_limits<float64>::digits == 53.
std::numeric_limits<float128>::digits == 113.

Для наиболее распространенного случая<radix ==2>,<std::numeric_limits<T>::digits>является число битов в представлении, не считая ни одного бита знака.

Для десятичного целого типа, когда<radix ==10>, это число десятичных цифр.

digits10

Константа<std::numeric_limits<T>::digits10>возвращает число десятичных цифр, которые могут быть представлены без изменения или потери.

Например,<numeric_limits<unsignedchar>::digits10>равно 2.

Это несколько непостижимое определение означает, что<unsigned char>может содержать десятичные значения<0..99>без потери точности или точности, обычно от усечения.

Если бы определение было 3, это означало бы, что он может содержать 0,999, но, как мы все знаем, 8-битный<unsigned char>может содержать только 0,255, а попытка сохранить 256 или более будет включать потерю или изменение.

Таким образом, для ограниченных целых чиселна одно меньше, чем число десятичных цифр, необходимо отображать наибольшее целое число<std::numeric_limits<T>::max()>. Это значение может использоваться для прогнозирования ширины компоновки, необходимой для

std::cout
  << std::setw(std::numeric_limits<short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  << std::showpos << (std::numeric_limits<short>::max)() // +32767
  << std::endl
  << std::setw(std::numeric_limits<short>::digits10 +1 +1)
  << (std::numeric_limits<short>::min)() << std::endl;   // -32767

Например,<unsignedshort>часто хранится в 16 битах, поэтому максимальное значение составляет 0xFFFF или 65535.

std::cout
  << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  << std::showpos << (std::numeric_limits<unsigned short>::max)() //  65535
  << std::endl
  << std::setw(std::numeric_limits<unsigned short>::digits10 +1 +1) // digits10+1, and +1 for sign.
  << (std::numeric_limits<unsigned short>::min)() << std::endl;   //      0

Для ограниченных типов плавающих точек, если мы создаем<double>со значением<digits10>(обычно 15) десятичных цифр,<1e15>или<1000000000000000>:

std::cout.precision(std::numeric_limits<double>::max_digits10);
double d =  1e15;
double dp1 = d+1;
std::cout << d << "\n" << dp1 << std::endl;
// 1000000000000000
// 1000000000000001
std::cout <<  dp1 - d << std::endl; // 1

И мы можем увеличить это значение до<1000000000000001>, как и ожидалось, и показать разницу.

Но если мы попытаемся повторить это с более чем 99 цифрами,

std::cout.precision(std::numeric_limits<double>::max_digits10);
double d =  1e16;
double dp1 = d+1;
std::cout << d << "\n" << dp1 << std::endl;
// 10000000000000000
// 10000000000000000
  std::cout << dp1 - d << std::endl; // 0 !!!

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

Так<digits10>число десятичных знаковгарантируетправильность.

Например, «круглые столы»<double>:

  • Если десятичная строка с максимумом<digits10>( == 15) значащими десятичными цифрами преобразуется в<double>, а затем преобразуется обратно в то же число значащих десятичных цифр, то окончательная строка будет соответствовать исходной строке с 15 десятичными цифрами.
  • Если число<double>с плавающей точкой преобразуется в десятичную строку с по меньшей мере 17 десятичными цифрами и затем преобразуется обратно в<double>, то результат будет двоичным, идентичным исходному значению<double>.

Для большинства целей вам, скорее всего, понадобится<std::numeric_limits<>::max_digits10>, число десятичных цифр, которые гарантируют, что изменение одного наименее значимого бита (ULP) создает другую десятичную строку цифр.

Для наиболее распространенного типа<double>с плавающей точкой<max_digits10>является<digits10+2>, но вы должны использовать C++11<max_digits10>, где это возможно (см.ниже).

max_digits10

<std::numeric_limits<T>::max_digits10>было добавлено для плавающей точки, потому что<digits10>десятичных цифр недостаточно, чтобы показать изменение по меньшей мере значительного бита (ULP), придавая загадочные дисплеи, такие как

0.666666666666667 != 0.666666666666667

От неудачи до «круглого пути», например:

double write = 2./3; // Any arbitrary value that cannot be represented exactly.
double read = 0;
std::stringstream s;
s.precision(std::numeric_limits<double>::digits10); // or `float64_t` for 64-bit IEE754 double.
s << write;
s >> read;
if(read != write)
{
  std::cout <<  std::setprecision(std::numeric_limits<double>::digits10)
    << read << " != " << write << std::endl;
}

Если вы хотите убедиться, что изменение одного наименее значимого бита (ULP) производит другую десятичную строку цифр, то<max_digits10>- это точность использования.

Например:

double pi = boost::math::double_constants::pi;
std::cout.precision(std::numeric_limits<double>::max_digits10);
std::cout << pi << std::endl; // 3.1415926535897931

будет отображаться π с максимально возможной точностью с использованием<double>.

Для более точного типа:

using namespace boost::multiprecision;
typedef number<cpp_dec_float<50> > cpp_dec_float_50; // 50 decimal digits.
using boost::multiprecision::cpp_dec_float_50;
cpp_dec_float_50 pi = boost::math::constants::pi<cpp_dec_float_50>();
std::cout.precision(std::numeric_limits<cpp_dec_float_50>::max_digits10);
std::cout << pi << std::endl;
// 3.141592653589793238462643383279502884197169399375105820974944592307816406

Для целых типов<max_digits10>зависит от реализации, но обычно<digits10 +2>. Это выходная ширина поля, требуемая для максимального значения типа T<std::numeric_limits<T>::max()>, включая знак и пространство.

Это позволит создать аккуратные колонны.

std::cout << std::setw(std::numeric_limits<int>::max_digits10) ...

Дополнительные две или три наименее значимые цифры являются «шумными» и могут быть «мусорными», но если вы хотите «объехать» - распечатать значение в виде десятичной строки и прочитать его обратно - (чаще всего во время сериализации и десериализации) вы должны использовать<os.precision(std::numeric_limits<T>::max_digits10)>.

[Note] Note

Для Microsoft Visual Studio 2010<std::numeric_limits<float>::max_digits10>ошибочно определяется как 8. Должно быть 9.

[Note] Note

Для Microsoft Visual Studio до 2013 года и формата по умолчанию, небольшой диапазон значений примерно от 0,0001 до 0,004, с значениями экспоненты от 3F2 до 3F6, неправильно вводится одним наименее значительным битом, вероятно, каждое третье значение значимо.

Обратный путь — это использование научного или экспоненциального формата<<<std::scientific>.

[Note] Note

BOOST_NO_CXX11_NUMERIC_LIMITS является подходящим макросом для определения того, реализован ли<std::numeric_limits<float>::max_digits10>на какой-либо платформе.

Если<max_digits10>недоступен, вы должны использовать формулу Каханадля плавающей точки типа Т.

В C++ уравнения для того, что Кахан (на стр. 4) описывает как «по крайней мере» и «по большей части»:

static long double const log10Two = 0.30102999566398119521373889472449L; // log10(2.)
static_cast<int>(floor((significand_digits - 1) * log10Two)); // == digits10  - 'at least' .
static_cast<int>(ceil(1 + significand_digits * log10Two)); // == max_digits10  - 'at most'.

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

max_digits10 = 2 + std::numeric_limits<T>::digits * 3010U/10000U;
// == 2 + std::numeric_limits<T>::digits for double and 64-bit long double.
// == 3 + std::numeric_limits<T>::digits for float,  80-bit long-double and __float128.

Часто фактические значения вычисляются для макросов пределов С:

#define FLT_MAXDIG10 (2+FLT_MANT_DIG * 3010U/10000U)  // 9
#define DBL_MAXDIG10 (2+ (DBL_MANT_DIG * 3010U)/10000U) // 17
#define LDBL_MAXDIG10 (2+ (LDBL_MANT_DIG * 3010U)/10000U) // 17 for MSVC, 18 for others.

Коэффициент 3010U/10000U составляетlog10(2) = 0,3010, который может быть оценен во время компиляции, используя только<short unsignedint>s, чтобы быть желательным<const>или<constexpr>(и обычно также<static>).

Усиленные макросы позволяют делать это портативно, см.BOOST_CONSTEXPR_OR_CONST или BOOST_STATIC_CONSTEXPR.

(См. такжеRichard P. Brent and Paul Zimmerman, Modern Computer ArithmeticEquation 3.8 на стр. 116).

Например, быть переносимым (включая отдельные платформы) для типа<T>, где<T>может быть:<float>,<double>,<long double>,<128-bitquadtype>,<cpp_bin_float_50>...

  typedef float T;
#if defined BOOST_NO_CXX11_NUMERIC_LIMITS
   // No max_digits10 implemented.
    std::cout.precision(max_digits10<T>());
#else
  #if(_MSC_VER <= 1600)
   //  Wrong value for std::numeric_limits<float>::max_digits10.
    std::cout.precision(max_digits10<T>());
  #else // Use the C++11 max_digits10.
     std::cout.precision(std::numeric_limits<T>::max_digits10);
  #endif
#endif
  std::cout << "std::cout.precision(max_digits10) = " << std::cout.precision() << std::endl; // 9
  double x = 1.2345678901234567889;
  std::cout << "x = " << x << std::endl; //

которые должны выводить:

std::cout.precision(max_digits10) = 9
x = 1.23456789
round_style

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

  • округление до ближайшего вверх или вниз (по умолчанию для типов с плавающей запятой).
  • Округление (к положительной бесконечности).
  • Округление вниз (к отрицательной бесконечности).
  • округление к нулю (целые типы).
  • без закругления (если десятичный радикс).
  • Режим округления не является определяемым.

Для целых типов<std::numeric_limits<T>::round_style>всегда стремится к нулю.

std::numeric_limits<T>::round_style == std::round_to_zero;

Десятичный тип,<cpp_dec_float>раундов без определенного направления, то есть он вообще не округляется. И поскольку есть несколько защитных цифр, это не совсем то же самое, что усечение (кругом к нулю).

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

std::numeric_limits<T>::round_style == std::round_to_nearest;

См. функцию<std::numeric_limits<T>::round_error>для максимальной ошибки (в ULP), которую может вызвать округление.

has_denorm_loss

<true>если потеря точности обнаруживается какденормализацияпотеря, а не как неточный результат.

Всегда<false>для целых типов.

<false>для всех типов, не имеющих<has_denorm>==<std::denorm_present>.

denorm_style

Денормализованные значенияпредставляют собой представления с переменным числом экспонентных битов, которые могут допускать постепенный отток, так что, если тип T равен<double>.

std::numeric_limits<T>::denorm_min() < std::numeric_limits<T>::min()

Тип может иметь любое из следующих<enum float_denorm_style>значений:

  • <std::denorm_absent>, если он не допускает денормализованных значений. (Всегда используется для всех целочисленных и точных типов).
  • <std::denorm_present>, если тип с плавающей точкой допускает денормализованные значения.
  • <std::denorm_indeterminate>, если не определено во время компиляции.
Tinyness before rounding

<boolstd::numeric_limits<T>::tinyness_before>

<true>если тип может определить, что значение слишком мало, чтобы его можно было представить как нормализованное значение, прежде чем округлять его.

Как правило, это верно для<is_iec559>встроенных типов с плавающей запятой, но неверно для целых типов.

Стандартно совместимые реализации IEEE 754 с плавающей точкой могут обнаруживать поток с плавающей точкой в три заранее определенных момента:

  1. После вычисления результата с абсолютным значением, меньшим<std::numeric_limits<T>::min()>, такая реализация обнаруживаеткрохотность перед округлением(например, UltraSparc).
  2. После округления результата до<std::numeric_limits<T>::digits>битов, если результат является крошечным, такая реализация обнаруживаеткрошечность после округления(например, SuperSparc).
  3. Если преобразование округленного крошечного результата в субнормальную форму привело к потере точности, такая реализация обнаруживаетпотерю денормы.

PrevUpHomeNext

Статья std::numeric_limits<> constants раздела Chapter 1. Boost.Multiprecision Numeric Limits может быть полезна для разработчиков на c++ и boost.




Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.



:: Главная :: Numeric Limits ::


реклама


©KANSoftWare (разработка программного обеспечения, создание программ, создание интерактивных сайтов), 2007
Top.Mail.Ru

Время компиляции файла: 2024-08-30 11:47:00
2025-05-19 18:25:58/0.012326955795288/0