К сожалению, я ничего не знаю о сервере SQL, но вот алгоритм, который избегает больших чисел, и программа C для его демонстрации.
Ключ, как отмечает chtz в их комментарии, заключается в том, чтобы избежать вычисления больших степеней и больших факториалов. Вводя произвольные имена, пусть
a(N) = pow( A, N)/factorial(N)
b(N) = Sum{ 0<=i<N | a(i)}
Затем мы можем записать вероятность для N> A как
P = N/(N-A) * a(N) / (b(N) + N/(N-A) * a(N))
Обратите внимание, что у нас есть
b(N+1) = b(N) + a(N)
a(N+1) = (A/(N+1))*a(N)
чтобы мы могли приступить к написанию кода на основе этих рекурсий. Но и a, и b становятся большими с увеличением N, поэтому я думаю, что лучше ввести еще одну функцию как
beta( N) = a(N)/b(N)
Тогда beta (1) = A, а beta (N) уменьшается (до нуля) когда N превышает значение A. В терминах бета-версии мы имеем
P = N/(N-A) * beta(N) / (1 + N/(N-A) * beta(N))
Небольшая алгебра дает эту рекурсию для бета-версии:
beta(N) = (A/N) * beta(N-1)/(1+beta(N-1))
и, как отмечалось выше,
beta(1) = A
Вот программа C, основанная на этих идеях:
#include <stdio.h>
#include <stdlib.h>
// compute beta(toN) from A and previous value of beta
static double beta_step( int A, int toN, double beta)
{
double f = A/(double)toN;
return f*beta/(1.0+beta);
}
int main( void)
{
int A = 140;
int np = 20; // number of probabilities to compute
// compute values for beta at N=1..A
double beta = A;
for( int N=2; N<=A; ++N)
{ beta = beta_step( A, N, beta);
}
// compute probabilities at N=A+1..A+np
for( int i=1; i<=np; ++i)
{
int N = A+i;
beta = beta_step( A, N, beta);
double f = (double)N/(double)i; // == N/(N-A)
double prob = f*beta/(f*beta + 1.0);
printf( "%d\t%f\n", N, prob);
}
return EXIT_SUCCESS;
}
Я скомпилировал это (используя довольно старинный g cc (4.8.5)) с
gcc -o erl -std=gnu99 -Wall erl.c