1

我使用 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 的幂,但之后它开始表现得很奇怪。

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

4

2 回答 2

7

你得到这个尴尬结果的原因是因为丢失了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

请注意这些值如何四舍五入为 2 3

于 2016-03-13T10:25:58.630 回答
0

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

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

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

于 2016-03-13T10:49:49.347 回答