奇怪的 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)。
我正在使用 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)。