数值极限
定义于头文件 <limits>
定义于头文件 | ||
template< class T > class numeric_limits; |
numeric_limits 类模板提供查询各种算术类型属性的标准化方式(例如 int 类型的最大可能值是 std::numeric_limits<int>::max() )。
鉴别以模算术处理溢出的类型
std::numeric_limits<T>::is_modulo
static const bool is_modulo; | (C++11 前) | |
static constexpr bool is_modulo; | (C++11 起) |
std::numeric_limits<T>::is_modulo 对所有可能 (C++11 前)以模算术处理溢出的算术类型 T
为 true 。模算术即若此类型的加法、减法、乘法或除法结果会落在范围 [min(), max()] 外,则这种运算返回的结果与期望值相差 max()-min()+1 的整数倍。
| (C++11 起) |
标准特化
T | std::numeric_limits<T>::is_modulo 的值 |
/* non-specialized */ | false |
bool | false |
char | 实现定义 |
signed char | 实现定义 |
unsigned char | true |
wchar_t | 实现定义 |
char8_t | true |
char16_t | true |
char32_t | true |
short | 实现定义 |
unsigned short | true |
int | 实现定义 |
unsigned int | true |
long | 实现定义 |
unsigned long | true |
long long | 实现定义 |
unsigned long long | true |
float | false |
double | false |
long double | false |
注意
尽管 C++11 标准仍然说“在大多数机器上,这对于有符号整数为 true
”,这是缺陷而且已被更正。准确措辞从 C++03 到 C++11 的更改使得 true 值不再与有符号整数溢出上的未定义行为兼容。因此,依赖于有符号溢出为未定义(为了优化机会)的实现现在对有符号整数设置 is_modulo
为 false
。见示例 GCC PR 22200 。
调用示例
#include <iostream>
#include <string>
#include <limits>
struct SName
{
};
//偏特化
struct SPartSpec
{
};
namespace std
{
template<>
struct numeric_limits<SPartSpec>
{
static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true;
static _GLIBCXX_USE_CONSTEXPR bool is_signed = true;
static _GLIBCXX_USE_CONSTEXPR bool is_integer = true;
static _GLIBCXX_USE_CONSTEXPR bool is_exact = true;
static _GLIBCXX_USE_CONSTEXPR bool has_infinity = true;
static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = true;
static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = true;
static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm = denorm_present;
static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = true;
static _GLIBCXX_USE_CONSTEXPR float_round_style round_style = round_toward_neg_infinity;
static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = true;
static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true;
};
}
int main()
{
std::cout << std::boolalpha;
std::cout << "std::numeric_limits<bool>::is_modulo: "
<< std::numeric_limits<bool>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char>::is_modulo: "
<< std::numeric_limits<char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<signed char>::is_modulo: "
<< std::numeric_limits<signed char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned char>::is_modulo: "
<< std::numeric_limits<unsigned char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<wchar_t>::is_modulo: "
<< std::numeric_limits<wchar_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char16_t>::is_modulo: "
<< std::numeric_limits<char16_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char32_t>::is_modulo: "
<< std::numeric_limits<char32_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<short>::is_modulo: "
<< std::numeric_limits<short>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned short>::is_modulo: "
<< std::numeric_limits<unsigned short>::is_modulo << std::endl;
std::cout << "std::numeric_limits<int>::is_modulo: "
<< std::numeric_limits<int>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned int>::is_modulo: "
<< std::numeric_limits<unsigned int>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long>::is_modulo: "
<< std::numeric_limits<long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned long>::is_modulo: "
<< std::numeric_limits<unsigned long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long long>::is_modulo: "
<< std::numeric_limits<long long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned long long>::is_modulo: "
<< std::numeric_limits<unsigned long long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<float>::is_modulo: "
<< std::numeric_limits<float>::is_modulo << std::endl;
std::cout << "std::numeric_limits<double>::is_modulo: "
<< std::numeric_limits<double>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long double>::is_modulo: "
<< std::numeric_limits<long double>::is_modulo << std::endl;
std::cout << "std::numeric_limits<std::string>::is_modulo: "
<< std::numeric_limits<std::string>::is_modulo << std::endl;
std::cout << "std::numeric_limits<SName>::is_modulo: "
<< std::numeric_limits<SName>::is_modulo << std::endl;
std::cout << "std::numeric_limits<SPartSpec>::is_modulo: "
<< std::numeric_limits<SPartSpec>::is_modulo << std::endl;
return 0;
}
输出
能无更改地表示的 radix 位数
std::numeric_limits<T>::digits
static const int digits; | (C++11 前) | |
static constexpr int digits; | (C++11 起) |
std::numeric_limits<T>::digits 的值是能无更改地表示类型 T
的 radix 底位数。对于整数类型,这是不含符号位和填充位(若存在)的位数。对于浮点类型,这是尾数的位数。
标准特化
T | std::numeric_limits<T>::digits 的值(假设无填充位) |
/* non-specialized */ | 0 |
bool | 1 |
char | CHAR_BIT - std::numeric_limits<char>::is_signed |
signed char | CHAR_BIT - 1 |
unsigned char | CHAR_BIT |
wchar_t | CHAR_BIT*sizeof(wchar_t) - std::numeric_limits<wchar_t>::is_signed |
char8_t | CHAR_BIT |
char16_t | CHAR_BIT*sizeof(char16_t) |
char32_t | CHAR_BIT*sizeof(char32_t) |
short | CHAR_BIT*sizeof(short)-1 |
unsigned short | CHAR_BIT*sizeof(short) |
int | CHAR_BIT*sizeof(int)-1 |
unsigned int | CHAR_BIT*sizeof(int) |
long | CHAR_BIT*sizeof(long)-1 |
unsigned long | CHAR_BIT*sizeof(long) |
long long | CHAR_BIT*sizeof(long long)-1 |
unsigned long long | CHAR_BIT*sizeof(long long) |
float | FLT_MANT_DIG |
double | DBL_MANT_DIG |
long double | LDBL_MANT_DIG |
调用示例
#include <iostream>
#include <string>
#include <limits>
#include <cstdint>
struct SName
{
};
//偏特化
struct SPartSpec
{
};
namespace std
{
template<>
struct numeric_limits<SPartSpec>
{
static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true;
static _GLIBCXX_USE_CONSTEXPR bool is_signed = true;
static _GLIBCXX_USE_CONSTEXPR bool is_integer = true;
static _GLIBCXX_USE_CONSTEXPR bool is_exact = true;
static _GLIBCXX_USE_CONSTEXPR bool has_infinity = true;
static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = true;
static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = true;
static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm = denorm_present;
static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = true;
static _GLIBCXX_USE_CONSTEXPR float_round_style round_style = round_toward_neg_infinity;
static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = true;
static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true;
static _GLIBCXX_USE_CONSTEXPR int digits = CHAR_BIT;
};
}
int main()
{
std::cout << std::boolalpha;
std::cout << "std::numeric_limits<bool>::digits: "
<< std::numeric_limits<bool>::digits << std::endl;
std::cout << "std::numeric_limits<char>::digits: "
<< std::numeric_limits<char>::digits << std::endl;
std::cout << "std::numeric_limits<signed char>::digits: "
<< std::numeric_limits<signed char>::digits << std::endl;
std::cout << "std::numeric_limits<unsigned char>::digits: "
<< std::numeric_limits<unsigned char>::digits << std::endl;
std::cout << "std::numeric_limits<wchar_t>::digits: "
<< std::numeric_limits<wchar_t>::digits << std::endl;
std::cout << "std::numeric_limits<char16_t>::digits: "
<< std::numeric_limits<char16_t>::digits << std::endl;
std::cout << "std::numeric_limits<char32_t>::digits: "
<< std::numeric_limits<char32_t>::digits << std::endl;
std::cout << "std::numeric_limits<short>::digits: "
<< std::numeric_limits<short>::digits << std::endl;
std::cout << "std::numeric_limits<unsigned short>::digits: "
<< std::numeric_limits<unsigned short>::digits << std::endl;
std::cout << "std::numeric_limits<int>::digits: "
<< std::numeric_limits<int>::digits << std::endl;
std::cout << "std::numeric_limits<unsigned int>::digits: "
<< std::numeric_limits<unsigned int>::digits << std::endl;
std::cout << "std::numeric_limits<long>::digits: "
<< std::numeric_limits<long>::digits << std::endl;
std::cout << "std::numeric_limits<unsigned long>::digits: "
<< std::numeric_limits<unsigned long>::digits << std::endl;
std::cout << "std::numeric_limits<long long>::digits: "
<< std::numeric_limits<long long>::digits << std::endl;
std::cout << "std::numeric_limits<unsigned long long>::digits: "
<< std::numeric_limits<unsigned long long>::digits << std::endl;
std::cout << "std::numeric_limits<float>::digits: "
<< std::numeric_limits<float>::digits << std::endl;
std::cout << "std::numeric_limits<double>::digits: "
<< std::numeric_limits<double>::digits << std::endl;
std::cout << "std::numeric_limits<long double>::digits: "
<< std::numeric_limits<long double>::digits << std::endl;
std::cout << "std::numeric_limits<std::string>::digits: "
<< std::numeric_limits<std::string>::digits << std::endl;
std::cout << "std::numeric_limits<SName>::digits: "
<< std::numeric_limits<SName>::digits << std::endl;
std::cout << "std::numeric_limits<SPartSpec>::digits: "
<< std::numeric_limits<SPartSpec>::digits << std::endl;
return 0;
}
int is_modulo()
{
std::cout << std::boolalpha;
std::cout << "std::numeric_limits<bool>::is_modulo: "
<< std::numeric_limits<bool>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char>::is_modulo: "
<< std::numeric_limits<char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<signed char>::is_modulo: "
<< std::numeric_limits<signed char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned char>::is_modulo: "
<< std::numeric_limits<unsigned char>::is_modulo << std::endl;
std::cout << "std::numeric_limits<wchar_t>::is_modulo: "
<< std::numeric_limits<wchar_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char16_t>::is_modulo: "
<< std::numeric_limits<char16_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<char32_t>::is_modulo: "
<< std::numeric_limits<char32_t>::is_modulo << std::endl;
std::cout << "std::numeric_limits<short>::is_modulo: "
<< std::numeric_limits<short>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned short>::is_modulo: "
<< std::numeric_limits<unsigned short>::is_modulo << std::endl;
std::cout << "std::numeric_limits<int>::is_modulo: "
<< std::numeric_limits<int>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned int>::is_modulo: "
<< std::numeric_limits<unsigned int>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long>::is_modulo: "
<< std::numeric_limits<long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned long>::is_modulo: "
<< std::numeric_limits<unsigned long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long long>::is_modulo: "
<< std::numeric_limits<long long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<unsigned long long>::is_modulo: "
<< std::numeric_limits<unsigned long long>::is_modulo << std::endl;
std::cout << "std::numeric_limits<float>::is_modulo: "
<< std::numeric_limits<float>::is_modulo << std::endl;
std::cout << "std::numeric_limits<double>::is_modulo: "
<< std::numeric_limits<double>::is_modulo << std::endl;
std::cout << "std::numeric_limits<long double>::is_modulo: "
<< std::numeric_limits<long double>::is_modulo << std::endl;
std::cout << "std::numeric_limits<std::string>::is_modulo: "
<< std::numeric_limits<std::string>::is_modulo << std::endl;
std::cout << "std::numeric_limits<SName>::is_modulo: "
<< std::numeric_limits<SName>::is_modulo << std::endl;
std::cout << "std::numeric_limits<SPartSpec>::is_modulo: "
<< std::numeric_limits<SPartSpec>::is_modulo << std::endl;
return 0;
}
输出
能无更改地表示的十进制位数
std::numeric_limits<T>::digits10
static const int digits10; | (C++11 前) | |
static constexpr int digits10 | (C++11 起) |
std::numeric_limits<T>::digits10 的值是类型 T
能无更改地表示的底 10 位数,即任何拥有这么多十进制有效数字的数能转换成 T
的值并转换回十进制形式,而不因舍入或上溢而更改。对于底 radix 类型,它是 digits (对于浮点类型是 digits-1 )的值乘 log
10(radix) 并向下取整。
标准特化
T | std::numeric_limits<T>::digits10 的值 |
/* non-specialized */ | 0 |
bool | 0 |
char | std::numeric_limits<char>::digits * std::log10(2) |
signed char | std::numeric_limits<signed char>::digits * std::log10(2) |
unsigned char | std::numeric_limits<unsigned char>::digits * std::log10(2) |
wchar_t | std::numeric_limits<wchar_t>::digits * std::log10(2) |
char8_t | std::numeric_limits<char8_t>::digits * std::log10(2) |
char16_t | std::numeric_limits<char16_t>::digits * std::log10(2) |
char32_t | std::numeric_limits<char32_t>::digits * std::log10(2) |
short | std::numeric_limits<short>::digits * std::log10(2) |
unsigned short | std::numeric_limits<unsigned short>::digits * std::log10(2) |
int | std::numeric_limits<int>::digits * std::log10(2) |
unsigned int | std::numeric_limits<unsigned int>::digits * std::log10(2) |
long | std::numeric_limits<long>::digits * std::log10(2) |
unsigned long | std::numeric_limits<unsigned long>::digits * std::log10(2) |
long long | std::numeric_limits<long long>::digits * std::log10(2) |
unsigned long long | std::numeric_limits<unsigned long long>::digits * std::log10(2) |
float | FLT_DIG /* IEEE float 为 6 */ |
double | DBL_DIG /* IEEE double 为 15 */ |
long double | LDBL_DIG /* 80 位 Intel long double 为 18 */ |
示例
8 位二进制类型能准确表示任何二位十进制数,但不能表示 3 位十进制数 256..999 。 digits10
对 8 位类型的值是 2 ( 8 * std::log10(2) 为 2.41 )
标准 32 位 IEEE 754 浮点类型拥有 24 位小数部分(写出 23 位,隐含一位),这可以建议它能表示 7 位十进制数字( 24 * std::log10(2) 为 7.22 ),但相对误差不统一,且一些有 7 位十进制数的浮点值不能在转换到 32 位浮点再转换回来后生存:最小的正数例子是 8.589973e9 ,它在来回舍入后变成 8.589974e9 。这些误差在表示中不能超过一位,而 digits10
按 (24-1)*std::log10(2) 计算,即 6.92 。向下取整结果导致值 6 。
类似地,16 字符串 9007199254740993 在文本->double->文本回环中不保持,它变为 9007199254740992 : 64 位 IEEE 754 double 类型仅保证 15 位的舍入回环。
调用示例
#include <iostream>
#include <string>
#include <limits>
#include <cstdint>
struct SName
{
};
//偏特化
struct SPartSpec
{
};
namespace std
{
template<>
struct numeric_limits<SPartSpec>
{
static _GLIBCXX_USE_CONSTEXPR bool is_specialized = true;
static _GLIBCXX_USE_CONSTEXPR bool is_signed = true;
static _GLIBCXX_USE_CONSTEXPR bool is_integer = true;
static _GLIBCXX_USE_CONSTEXPR bool is_exact = true;
static _GLIBCXX_USE_CONSTEXPR bool has_infinity = true;
static _GLIBCXX_USE_CONSTEXPR bool has_quiet_NaN = true;
static _GLIBCXX_USE_CONSTEXPR bool has_signaling_NaN = true;
static _GLIBCXX_USE_CONSTEXPR float_denorm_style has_denorm = denorm_present;
static _GLIBCXX_USE_CONSTEXPR bool has_denorm_loss = true;
static _GLIBCXX_USE_CONSTEXPR float_round_style round_style = round_toward_neg_infinity;
static _GLIBCXX_USE_CONSTEXPR bool is_iec559 = true;
static _GLIBCXX_USE_CONSTEXPR bool is_bounded = true;
static _GLIBCXX_USE_CONSTEXPR bool is_modulo = true;
static _GLIBCXX_USE_CONSTEXPR int digits = CHAR_BIT;
static _GLIBCXX_USE_CONSTEXPR int digits10 = CHAR_BIT;
};
}
int main()
{
std::cout << std::boolalpha;
std::cout << "std::numeric_limits<bool>::digits10: "
<< std::numeric_limits<bool>::digits10 << std::endl;
std::cout << "std::numeric_limits<char>::digits10: "
<< std::numeric_limits<char>::digits10 << std::endl;
std::cout << "std::numeric_limits<signed char>::digits10: "
<< std::numeric_limits<signed char>::digits10 << std::endl;
std::cout << "std::numeric_limits<unsigned char>::digits10: "
<< std::numeric_limits<unsigned char>::digits10 << std::endl;
std::cout << "std::numeric_limits<wchar_t>::digits10: "
<< std::numeric_limits<wchar_t>::digits10 << std::endl;
std::cout << "std::numeric_limits<char16_t>::digits10: "
<< std::numeric_limits<char16_t>::digits10 << std::endl;
std::cout << "std::numeric_limits<char32_t>::digits10: "
<< std::numeric_limits<char32_t>::digits10 << std::endl;
std::cout << "std::numeric_limits<short>::digits10: "
<< std::numeric_limits<short>::digits10 << std::endl;
std::cout << "std::numeric_limits<unsigned short>::digits10: "
<< std::numeric_limits<unsigned short>::digits10 << std::endl;
std::cout << "std::numeric_limits<int>::digits10: "
<< std::numeric_limits<int>::digits10 << std::endl;
std::cout << "std::numeric_limits<unsigned int>::digits10: "
<< std::numeric_limits<unsigned int>::digits10 << std::endl;
std::cout << "std::numeric_limits<long>::digits10: "
<< std::numeric_limits<long>::digits10 << std::endl;
std::cout << "std::numeric_limits<unsigned long>::digits10: "
<< std::numeric_limits<unsigned long>::digits10 << std::endl;
std::cout << "std::numeric_limits<long long>::digits10: "
<< std::numeric_limits<long long>::digits10 << std::endl;
std::cout << "std::numeric_limits<unsigned long long>::digits10: "
<< std::numeric_limits<unsigned long long>::digits10 << std::endl;
std::cout << "std::numeric_limits<float>::digits10: "
<< std::numeric_limits<float>::digits10 << std::endl;
std::cout << "std::numeric_limits<double>::digits10: "
<< std::numeric_limits<double>::digits10 << std::endl;
std::cout << "std::numeric_limits<long double>::digits10: "
<< std::numeric_limits<long double>::digits10 << std::endl;
std::cout << "std::numeric_limits<std::string>::digits10: "
<< std::numeric_limits<std::string>::digits10 << std::endl;
std::cout << "std::numeric_limits<SName>::digits10: "
<< std::numeric_limits<SName>::digits10 << std::endl;
std::cout << "std::numeric_limits<SPartSpec>::digits10: "
<< std::numeric_limits<SPartSpec>::digits10 << std::endl;
return 0;
}