我的代码:
int main()
{
long long a = pow(2,63) - 1;
long long b = pow(2,63);
double c = pow(2,63) - 1;
double d = pow(2,63);
printf("%lld %lld \n%f %f \n%lld %lld\n", a, b, c, d, (long long)c, (long long)d);
return 0;
}其结果是(与gcc在win7 x64中的代码库):
9223372036854775807 9223372036854775807
9223372036854775800.000000 9223372036854775800.000000
-9223372036854775808 -9223372036854775808问题:
为什么是a == b?
我知道c == d是因为double的精确性。
但是为什么(long long)c和(long long)d不是9223372036854775800呢?
以及为什么(long long)c != a和(long long)d != b
发布于 2013-10-08 14:13:29
pow(2,63) - 1全部采用双精度浮点算法实现.特别是,-1被转换为-1.0,这太小了,不重要。
发布于 2013-10-08 15:07:55
为什么是== b?
因为您的编译器(gcc)计算了用于初始化a和b的值,并找到了(已证明?)两者都匹配或超过了long long的最大可能值,因此它使用最大值LLONG_MAX (或平台上的0x7FFFFFFFFFFFFFFF或9223372036854775807 )初始化了这两个值。
请注意(正如Pascal所指出的),这是未定义的行为,是在初始化double和b时将a转换为b时发生的溢出造成的。gcc如前所述处理这一问题,而其他编译器则可以以不同方式处理这一问题。
我知道c ==d是因为它的精度
c和d保持相同值的原因确实是因为double的精度:
pow(2, 63)可以用分数1和指数63精确地表示。pow(2, 63) - 1它之所以没有显示9223372036854775808 (存储在c和d中的精确值),是因为printf的精度,在您的平台上显然只有17位数字。你可能会强迫它显示更多的使用例如。%20.0f,但在Windows上,这很可能不会因为这只虫子而有什么不同。
为什么(长长)c和(长长)d不是9223372036854775800?
因为c和d保存了值9223372036854775808,或者0x8000000000000000,当打印为有符号的值时,值变为-9223372036854775808。
请注意,这再次是未定义的行为(由于签名溢出)。
为什么(长长)c != a和(长长)d != b?
因为它们是以不同的方式计算出来的。a和b由编译器计算,而(long long) c和(long long) d则在运行时计算。
通常情况下,这些不同的计算方法应该会产生相同的结果,但我们在这里处理的是未定义的行为(正如前面所解释的),所以任何事情都会发生。在您的示例中,编译器的结果与运行时的结果不同。
发布于 2013-10-08 14:13:01
因为pow返回双倍和双倍丢失的精度。这就是为什么a==b。
https://stackoverflow.com/questions/19249975
复制相似问题