为什么uint64_t无法正常显示pow(2,64) - 1?

问题描述 投票:-1回答:2

我试图理解为什么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
c++ floating-point double uint64
2个回答
5
投票

浮点数具有有限的精度。

在您的系统上(通常,假设为binary64 IEEE-754格式)18446744073709551615不是具有double格式表示的数字。具有表示的最接近的数字恰好是18446744073709551616

将两个具有完全不同大小的浮点数相减(并相加)通常会产生错误。相对于较小的操作数,此错误可能很重要。在18446744073709551616. - 1. -> 18446744073709551616.的情况下,减法的误差是1,实际上是与较小的操作数相同的值。

当浮点值转换为整数类型,并且该值不能适合整数类型时,程序的行为是未定义的 - 即使整数类型是无符号的。


0
投票

pow(2, 64) - 1double表达式,而不是int,因为pow没有任何重载返回整数类型。文字1将被提升为与pow相同的等级

但是因为IEEE-754双精度只有64位长,所以永远不能存储64位或更多位的值,如264-1

所以pow(2, 64) - 1将四舍五入到最接近的可表示值,即pow(2, 64)本身,而pow(2, 64) - 1 == pow(2, 64)将导致1.最小值比它小18446744073709549568 = 264 - 2048.你可以用std::nextafter查看

在某些平台上(特别是x86,除了在MSVC上)long double确实有64 bits of significand,因此在这种情况下你将获得正确的值。 following snippet

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

在许多其他平台上,double可能是IEEE-754 quadruple-precisiondouble-double。两者都有超过64位的有效数字,所以你可以做同样的事情。但当然开销会更高

无论如何,你不应该从一开始就使用浮点类型进行整数数学运算。不仅计算pow(2, x)1ULL << x慢得多,它还会导致你看到的问题,因为double的精度有限。如果编译器支持该类型,请使用uint64_t max2 = -1((unsigned __int128)1ULL << 64) - 1

© www.soinside.com 2019 - 2024. All rights reserved.