奇怪的 unsigned long long int 行为

Strange unsigned long long int behavior

我正在使用 unsigned long long int 进行一些计算,但是

std::cout << std::setprecision(30) << 900000000000001i64+4*pow(10, 16);

给出输出:40900000000000000

还有这个

std::cout << std::setprecision(30) << 900000000000011i64+4*pow(10, 16);

给出输出:40900000000000008

现在我不知道发生了什么 我尝试删除 i64 尝试打印 4*pow(10, 16) 给出正确的结果 40000000000000000 也尝试直接打印 40900000000000011,它打印正确的结果。它适用于 10^14 的幂,但之后它开始表现得很奇怪。

有人可以解释发生了什么吗?

你得到这个尴尬结果的原因是因为丢失了 double 类型中最低有效位的值。 double 尾数只能容纳大约 15 位十进制数字和恰好 52 位二进制数字 (wiki)。

900000000000001i64+4*pow(10, 16) 将转换为双修剪所有低位。在你的情况下,有 3 个。

示例:

std::cout << std::setprecision(30);
std::cout << 900000000000001i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000002i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000003i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000004i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000005i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000006i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000007i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000008i64 + 4 * pow(10, 16) << endl;
std::cout << 900000000000009i64 + 4 * pow(10, 16) << endl;

将产生结果:

40900000000000000
40900000000000000
40900000000000000
40900000000000000
40900000000000008
40900000000000008
40900000000000008
40900000000000008
40900000000000008
40090000000000008

注意值是如何四舍五入 到 23.

请尝试这段代码(注意那里的显式类型转换)。

typedef unsigned long long ULONG64; //Not a must, but just for code clarity

std::cout << std::setprecision(30) << 900000000000001i64 + (ULONG64)(4 * pow(10, 16));
//output -> 40900000000000001
std::cout << std::setprecision(30) << 900000000000011i64 + (ULONG64)(4 * pow(10, 16));
//output -> 40900000000000011

您必须告诉编译器对 pow(...) 函数返回的双精度类型的结果进行显式类型转换(到 ULONG64)。