为什么使用int64_t给出错误的结果,而double工作正如预期的简单整数乘法

时间:2018-05-25 14:51:20

标签: c++ int double factorial

这是我的代码:

0

打印

1.37847e+11

这是错误的答案,但如果我将整数类型更改为double将打印<%= form_for @changeset, image_path(@conn, :create), [multipart: true], fn f -> %> 这是正确的答案,我的问题是为什么使用int64_t给我错误的答案

3 个答案:

答案 0 :(得分:9)

  

和int64_t不会溢出

但确实如此。为了调试这样的事情,你可以在GCC或clang中使用-fsanitize=signed-integer-overflow(隐含-fsanitize=undefined)来运行,看看:

  

运行时错误:有符号整数溢出:21 * 2432902008176640000无法在类型&#39; long&#39;中表示   运行时错误:有符号整数溢出:2432902008176640000 * 2432902008176640000无法用类型&#39; long&#39;

表示

答案 1 :(得分:5)

40!约为8e47。 64位有符号整数最多可以保持2^63-1,大约1e19

factorial(40)确实溢出,并且由于有符号整数类型的溢出是未定义的行为,因此无法解释您观察到的任何内容。

答案 2 :(得分:5)

欢迎来到有限精度数字的世界!事实(40)是815915283247897734345611269596115894272000000000或0x8eeae81b84c7f27e080fde64ff05254000000000,即使在uint64_t中也不适合128位long long,因为它实际上需要160位!

但二项式系数40,20确实可以使用uint64_t计算,只要你使用人类在计算机到处前所使用的正确算法:

integer binomial_coefficient(integer n, integer r) {
    integer bc = 1;
    integer q = n - r;
    for(integer i=1; i<=r; i++) {
        br = br * (q + i) / i;
    }
    return bc;
}

这个将为您提供正确的值137846528820,没有溢出。

(上面的函数省略了r&lt; = n / 2的测试,可以进行额外的优化,因为Cn,p是构造Cn,n-p)