Visual Studio中的long long值

Pet*_*ter 10 c++ long-long

我们知道-2*4 ^ 31 + 1 = -9.223.372.036.854.775.807,你可以在long long中存储的最低值,如下所述:整数类型在C++中存储的值的范围.所以我有这个操作:

#include <iostream>

unsigned long long pow(unsigned a, unsigned b) { 
    unsigned long long p = 1; 
    for (unsigned i = 0; i < b; i++) 
        p *= a; 
    return p; 
}

int main()
{
    long long nr =  -pow(4, 31) + 5 -pow(4,31);
    std::cout << nr << std::endl;
}
Run Code Online (Sandbox Code Playgroud)

为什么它显示-9.223.372.036.854.775.808而不是-9.223.372.036.854.775.803?我正在使用Visual Studio 2015.

Mar*_*ica 15

这是一个非常讨厌的小问题,有三个(!)原因.

首先,存在浮点运算是近似的问题.如果编译器选择一个pow返回float或double 的函数,那么4**31是如此之大,以至于5小于1ULP(精度最低的单位),所以添加它将无效(换句话说,4.0**31 + 5 = = 4.0**31).乘以-2可以毫无损失地完成,并且结果可以long long作为错误的答案存储在一起而不会丢失:-9.223.372.036.854.775.808.

其次,标准头可以包括其他标准头,但不是必需的.显然,Visual Studio的<iostream>包含版本<math.h>(pow在全局命名空间中声明),但Code :: Blocks版本没有.

第三,OP的pow函数没有被选中,因为他传递参数4,并且31它们都是类型int,并且声明的函数具有类型的参数unsigned.从C++ 11开始,有很多重载(或函数模板)std::pow.这些都返回floatdouble(除非其中一个参数属于类型long double- 这里不适用).

因此,重载std::pow将是更好的匹配...具有双返回值,并且我们得到浮点舍入.

故事的道德:除非你真的知道自己在做什么,否则不要编写与标准库函数同名的函数!