首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >c++中的“双长长”混淆

c++中的“双长长”混淆
EN

Stack Overflow用户
提问于 2013-10-08 14:07:26
回答 5查看 5.9K关注 0票数 3

我的代码:

代码语言:javascript
复制
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中的代码库):

代码语言:javascript
复制
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

EN

回答 5

Stack Overflow用户

发布于 2013-10-08 14:13:29

pow(2,63) - 1全部采用双精度浮点算法实现.特别是,-1被转换为-1.0,这太小了,不重要。

票数 4
EN

Stack Overflow用户

发布于 2013-10-08 15:07:55

为什么是== b?

因为您的编译器(gcc)计算了用于初始化ab的值,并找到了(已证明?)两者都匹配或超过了long long的最大可能值,因此它使用最大值LLONG_MAX (或平台上的0x7FFFFFFFFFFFFFFF9223372036854775807 )初始化了这两个值。

请注意(正如Pascal所指出的),这是未定义的行为,是在初始化doubleb时将a转换为b时发生的溢出造成的。gcc如前所述处理这一问题,而其他编译器则可以以不同方式处理这一问题。

我知道c ==d是因为它的精度

cd保持相同值的原因确实是因为double的精度:

  • pow(2, 63)可以用分数1和指数63精确地表示。
  • 不能准确地表示pow(2, 63) - 1

它之所以没有显示9223372036854775808 (存储在cd中的精确值),是因为printf的精度,在您的平台上显然只有17位数字。你可能会强迫它显示更多的使用例如。%20.0f,但在Windows上,这很可能不会因为这只虫子而有什么不同。

为什么(长长)c和(长长)d不是9223372036854775800?

因为cd保存了值9223372036854775808,或者0x8000000000000000,当打印为有符号的值时,值变为-9223372036854775808

请注意,这再次是未定义的行为(由于签名溢出)。

为什么(长长)c != a和(长长)d != b?

因为它们是以不同的方式计算出来的。ab由编译器计算,而(long long) c(long long) d则在运行时计算。

通常情况下,这些不同的计算方法应该会产生相同的结果,但我们在这里处理的是未定义的行为(正如前面所解释的),所以任何事情都会发生。在您的示例中,编译器的结果与运行时的结果不同。

票数 2
EN

Stack Overflow用户

发布于 2013-10-08 14:13:01

因为pow返回双倍和双倍丢失的精度。这就是为什么a==b

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/19249975

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档