c – long double vs long int

我正在做一个计算彩票的概率的程序.
规格选择47中的5个数字和27个中的1个

所以我做了以下:

#include <iostream>

long int choose(unsigned n,unsigned k);
long int factorial(unsigned n);

int main(){
    using namespace std;
    long int regularProb,megaProb;
    regularProb = choose(47,5);
    megaProb = choose(27,1);
    cout << "The probability of the correct number is 1 out of " << (regularProb * megaProb) << endl;

    return 0;
}

long int choose(unsigned n,unsigned k){    
    return factorial(n) / (factorial(k) * factorial(n-k));
}

long int factorial(unsigned n){
    long int result = 1;
    for (int i=2;i<=n;i++) result *= i;
    return result;
}

但是程序不行.程序计算30秒,然后给我进程4退出代码-1,073,741,676我必须将所有的长整型变为长双倍,但是失去精度.是因为long int对于大价值来说太短了吗?虽然我以为long int现在是64位?我的编译器是g win32(64位主机).

解决方法

长时间是64位还是不依赖于型号. Windows uses a 32-bit long.如果需要确保它是64位,请使用 int64_t from <stdint.h>.

但是即使长达64位,它仍然太小,无法进行阶乘(47).

47!  == 2.58623242e+59
2^64 == 1.84467441e+19

虽然47C5比这个小.

你不应该使用nCr == n!/(r!(n-r)!)直接进行计算,因为它容易溢出.取而代之的是n!/(n-r)!到get

47 * 46 * 45 * 44 * 43
  C  = ----------------------
47 5    5 *  4 *  3 *  2 *  1

这可以由32位整数进行管理.

BTW,为@咖啡的问题:双精度只有53位,其中47!需要154位. 47!和42!以双倍代表

47! = (0b10100100110011011110001010000100011110111001100100100 << 145) ± (1 << 144)
42! = (0b11110000010101100000011101010010010001101100101001000 << 117) ± (1 << 116)

所以47! /(42!×5!)的可能范围将是

0b101110110011111110011 = 1533939                       53 bits
                                                              v
max = 0b101110110011111110011.000000000000000000000000000000001001111...
val = 0b101110110011111110010.111111111111111111111111111111111010100...
min = 0b101110110011111110010.111111111111111111111111111111101011010...

这足以得到确切的值47C5.

相关文章

本程序的编译和运行环境如下(如果有运行方面的问题欢迎在评...
水了一学期的院选修,万万没想到期末考试还有比较硬核的编程...
补充一下,先前文章末尾给出的下载链接的完整代码含有部分C&...
思路如标题所说采用模N取余法,难点是这个除法过程如何实现。...
本篇博客有更新!!!更新后效果图如下: 文章末尾的完整代码...
刚开始学习模块化程序设计时,估计大家都被形参和实参搞迷糊...