为什么UINT64_T不能正确显示POW(2,64)-1
Why uint64_t cannot show pow(2, 64) - 1 properly?
我试图了解为什么uint64_t
类型不能正确显示pow(2,64)-1
。Cplusplus标准是199711L。
我在C 98标准下检查了pow()
功能
double pow (double base , double exponent);
float pow (float base , float exponent);
long double pow (long double base, long double exponent);
double pow (double base , int exponent);
long double pow (long double base, int exponent);
所以我写了以下片段
double max1 = (pow(2, 64) - 1);
cout << max1 << endl;
uint64_t max2 = (pow(2, 64) - 1);
cout << max2 << endl;
uint64_t max3 = -1;
cout << max3 << endl;
输出为:
max1: 1.84467e+019
max2: 9223372036854775808
max3: 18446744073709551615
浮点数的精度有限。
在您的系统上(通常,假设Binary64 IEEE-754格式)18446744073709551615
不是具有double
格式表示的数字。确实具有表示形式的最接近的数字恰好是18446744073709551616
。
减去(并添加)两个大小不同幅度的浮点数通常会产生错误。对于较小的操作数,此错误可能很重要。在18446744073709551616. - 1. -> 18446744073709551616.
的情况下,减法的误差为1,实际上与较小的操作数相同。
当浮点值转换为整数类型,并且该值不能适合整数类型时,即使整数类型未签名,程序的行为也是不确定的。
tl; dr :不是不是 uint64_t
类型无法正确显示 pow(2,64)-1
strong> double
无法精确存储2 64 -1 由于缺乏显着范围。您只能使用具有64位精度或更多位的类型(例如许多平台上的long double
)。尝试std::pow(2.0L, 64) - 1.0L
(注意L
后缀)或powl(2.0L, 64) - 1.0L;
,请参见
无论如何,您从一开始就不应将浮点类型用于整数数学。计算pow(2, x)
的不仅要比1ULL << x
慢得多,而且由于double
的精确度有限,还会导致您看到的问题。如果编译器支持__int128
uint64_t max2 = -1
或((unsigned __int128)1ULL << 64) - 1
pow(2, 64) - 1
是double
表达式,不是 int
,因为pow
没有任何返回积分类型的过载。整数1
将被提升为与pow
但是,由于IEEE-754双重精度仅为64位长,因此您可以从不P> 因此, 在某些平台上(尤其是x86,除了在MSVC上) 打印出 您可以清楚地看到 在许多其他平台上,pow(2, 64) - 1
将被四舍五入到pow(2, 64)
本身的最接近代表值,并且pow(2, 64) - 1 == pow(2, 64)
将导致1.最大的值。SUP>-2048。您可以使用std::nextafter
long double
确实具有64位显着的,因此在这种情况下您将获得正确的值。以下片段double max1 = pow(2, 64) - 1;
std::cout << "pow(2, 64) - 1 = " << std::fixed << max1 << 'n';
std::cout << "Previous representable value: " << std::nextafter(max1, 0) << 'n';
std::cout << (pow(2, 64) - 1 == pow(2, 64)) << 'n';
long double max2 = pow(2.0L, 64) - 1.0L;
std::cout << std::fixed << max2 << 'n';
pow(2, 64) - 1 = 18446744073709551616.000000
Previous representable value: 18446744073709549568.000000
1
18446744073709551615.000000
long double
可以按预期存储正确的值double
可能是IEEE-754四倍体或双双。两者都有超过64位的显着性,因此您可以做同样的事情。但是,当然,开销将更高
- 比较并显示使用最小值(a,b)和最大值(a、b)升序排列的4个数字
- C++,OpenCV,尝试显示图像时"OpenCV(4.3.0) Error: Assertion failed (size.width>0 && size.height>0)"此错误
- 字符串-C++后显示的随机字符
- 继承期间显示未知行为的子类
- 仅使用绝对值对数组进行排序,并在C++中显示实际值
- 程序崩溃并显示"std::out_of_range"错误
- 如何在C++中用std::cout正确显示带十六进制的字符串文本
- 为什么在C的循环中使用printf的Rust代码不显示输出,而在C++的循环中显示std::cout
- 在C++中如何在没有pow的情况下进行基础计算
- 从数据库实时显示QT c++中的数据
- 当使用比格式支持的精度更高的精度来显示数字时,会写出什么数据
- 显示错误输出的简单数组排序程序
- Qt自定义QPush按钮未显示在布局上
- C++射线示踪剂ppm表示没有足够的数据来显示图像
- 显示基于用户输入的整数的字符
- 使用QTreeView,如何通过调用函数只突出显示特定的行/列
- 理解GCC中的std::pow实现
- 应用程序崩溃并显示"symbol _ZdlPvm, version Qt_5 not defined in file libQt5Core.so.5 with link time reference"
- 示例外壳应用程序显示的 V8 "segmentation fault (core dumped)"错误
- 为什么UINT64_T不能正确显示POW(2,64)-1