long double vs long int

时间:2011-05-10 15:50:28

标签: c++

我正在做一个计算彩票概率的程序。 规范是选择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秒,然后给我Process 4 exited with code -1,073,741,676我必须将所有long int更改为long double,但这会失去精度。是因为long int对于大值来说太短了吗?虽然我认为现在的长篇是64位?我的编译器是g ++ win32(64位主机)。

4 个答案:

答案 0 :(得分:18)

long是否为64位取决于模型。 Windows uses a 32-bit long。如果您需要确保它是64位,请使用int64_t from <stdint.h>

但即使long为64位,它仍然太小而无法容纳factorial(47)

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

虽然 47 C 5 比这个小。

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

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

这甚至可以通过32位整数进行管理。


BTW,对于@ Coffee的问题:double只有53位的精度,其中47!需要154位。 47!和42!在double中表示的将是

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...

这足以得到准确的值 47 C 5

答案 1 :(得分:3)

要使用64位长,您应该使用long long(as mentioned here)

答案 2 :(得分:0)

KennyTM说得对,无论你使用什么类型,你都会溢出。您需要更聪明地处理问题并分解大量工作。如果你对一个近似的答案没问题,那么看看斯特林的近似值:

Ln(n!) ~ n Ln(n) - n

所以,如果你有

n!/(k!*(n-k)!)

你可以说那是

e(ln(n!/(k!*(n-k)!)))
经过一些数学考试(仔细检查以确保我做对了)

e(n*ln(n)-k*ln(k)-(n-k)*ln(n-k))

那不应该溢出(但这是一个近似的答案)

答案 3 :(得分:0)

使用标准unsigned long 32位算法,很容易计算高达47C5及以上的二项式系数而不会溢出。请参阅我对此问题的回复:https://math.stackexchange.com/questions/34518/are-there-examples-where-mathematicians-needs-to-calculate-big-combinations/34530#comment-76389