简体   繁体   English

奇怪的unsigned long long int行为

[英]Strange unsigned long long int behavior

I was using unsigned long long int for some calculations but 我正在使用unsigned long long int进行一些计算,但是

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

Gives Output: 40900000000000000 输出: 40900000000000000

and this 和这个

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

Gives Output: 40900000000000008 输出: 40900000000000008

Now i have no idea what is happening i tried removing i64 tries printing 4*pow(10, 16) gives the correct result 40000000000000000 also tried printing 40900000000000011 directly, it prints the correct result. 现在,我不知道发生了什么事我试图消除i64尝试打印4*pow(10, 16)给出正确的结果40000000000000000也试图打印40900000000000011直接,它打印正确的结果。 It works fine for power of 10^14 but after that it starts to behave strangely. 对于10 ^ 14的幂,它可以正常工作,但是此后它开始表现异常。

Can someone explain what is happening? 有人可以解释发生了什么吗?

The reason you get this awkward result is because of loosing the values of the least significant bits in double type. 您得到此尴尬结果的原因是因为丢失了double类型的最低有效位的值。 double mantissa can only hold about 15 decimal digits and exactly 52 binary digits ( wiki ). double尾数只能容纳大约15个十进制数字和正好52个二进制数字( Wiki )。

900000000000001i64+4*pow(10, 16) will be converted to double trimming all lower bits. 900000000000001i64+4*pow(10, 16)将转换为对所有低位进行双重修整。 In you case there are 3 of them. 在您的情况下,其中有3个。

Example: 例:

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;

will produce result: 将产生结果:

40900000000000000
40900000000000000
40900000000000000
40900000000000000
40900000000000008
40900000000000008
40900000000000008
40900000000000008
40900000000000008
40090000000000008

Notice how the values are rounded to 2 3 . 注意如何将值四舍五入为2 3

Please try this code (notice the explicit type conversion there). 请尝试以下代码(请注意此处的显式类型转换)。

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

You have to tell compiler to do explicit type conversion (to ULONG64) on result returned by pow(...) function which is of type double. 您必须告诉编译器对pow(...)函数返回的结果进行显式类型转换(转换为ULONG64),类型为double。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM