[英]Optimization of C code for hypergeometric distribution
我必須優化給定的 C 代碼:-
#include<sys/time.h>
#include<stdio.h>
#define GAP(start, end) ((end.tv_usec-start.tv_usec)+(end.tv_sec-start.tv_sec)*1000000)
void main(){
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
/* START OF BLOCK */
long int n, N, e, E, e_choose_i, E_e_choose_N_i, E_choose_N;
float p_value = 0;
long int i, var1, var2, var3, var4; // Temporary variables
fscanf(stdin, "%ld%ld%ld%ld", &n, &N, &e, &E);
for(i = n; i <= N; i++){
for(var1 = 1, var4 = 2; var4 <= e; var4++)
var1 = var1 * var4; // Computes e!
for(var2 = 1, var4 = 2; var4 <= i; var4++)
var2 = var2 * var4; // Computes i!
for(var3 = 1, var4 = 2; var4 <= e-i; var4++)
var3 = var3 * var4; // Computes (e-i)!
e_choose_i = var1/(var2*var3); // Computes (e choose i)
for(var1 = 1, var4 = 2; var4 <= (E-e); var4++)
var1 = var1 * var4; // Computes (E-e)!
for(var2 = 1, var4 = 2; var4 <= (N-i); var4++)
var2 = var2 * var4; // Computes (N-i)!
for(var3 = 1, var4 = 2; var4 <= ((E-e)-(N-i)); var4++)
var3 = var3 * var4; // Computes ((E-e)-(N-i))!
E_e_choose_N_i = var1/(var2*var3); // Computes ((E-e) choose (N-i))
p_value += e_choose_i*E_e_choose_N_i;
}
for(var1 = 1, var4 = 2; var4 <= E; var4++)
var1 = var1 * var4; // Computes E!
for(var2 = 1, var4 = 2; var4 <= N; var4++)
var2 = var2 * var4; // Computes N!
for(var3 = 1, var4 = 2; var4 <= E-N; var4++)
var3 = var3 * var4; // Computes (E-N)!
E_choose_N = var1/(var2*var3); // Computes (E choose N)
p_value /= E_choose_N;
/* END OF BLOCK */
gettimeofday(&end_time, NULL);
printf("p-value = %f (%d microseconds)", p_value, (int) GAP(start_time, end_time));
}
我使用動態編程方法來找到二項式系數並將代碼修改為:-
#include<sys/time.h>
#include<stdio.h>
#define GAP(start, end) ((end.tv_usec-start.tv_usec)+(end.tv_sec-start.tv_sec)*1000000)
void main(){
struct timeval start_time, end_time;
gettimeofday(&start_time, NULL);
/* START OF BLOCK */
long int n, N, e, E, e_choose_i, E_e_choose_N_i, E_choose_N;
float p_value = 0;
long int i; //var1, var2, var3, var4; // Temporary variables
int p,q,r;
fscanf(stdin, "%ld%ld%ld%ld", &n, &N, &e, &E);
for(i = n; i <= N; i++){
long int C[e+1][i+1];
for(p=0;p<=e;p++)
{
r=(p<i)?p:i;
for(q=0;q<=r;q++)
{
if(q==0 || q==p)
C[p][q]=1;
else
C[p][q]=C[p-1][q-1]+C[p-1][q];
}
}
e_choose_i=C[e][i];
long int C1[E-e+1][N-i+1];
for(p=0;p<=E-e;p++)
{
r= (p<N-i)?p:N-i ;
for(q=0;q<=r;q++)
{
if(q==0 || q==p)
C1[p][q]=1;
else
C1[p][q]=C1[p-1][q-1]+C1[p-1][q];
}
}
E_e_choose_N_i = C1[E-e][N-i]; // Computes ((E-e) choose (N-i))
p_value += e_choose_i*E_e_choose_N_i;
}
long int C2[E+1][N+1];
for(p=0;p<=E;p++)
{
r= (p<N)?p:N ;
for(q=0;q<=r;q++)
{
if(q==0 || q==p)
C2[p][q]=1;
else
C2[p][q]=C2[p-1][q-1]+C2[p-1][q];
}
}
E_choose_N = C2[E][N]; // Computes (E choose N)
p_value /= E_choose_N;
/* END OF BLOCK */
gettimeofday(&end_time, NULL);
printf("p-value = %f (%d microseconds)", p_value, (int) GAP(start_time, end_time));
}
較小的值例如 n=2,N=3,e=3 和 E=7 花費的時間更少,但對於較大的值(例如 n=3,N=8,e=10 和 E=15)花費更多的時間. 如何針對大值對其進行優化。 請幫忙。
正如dmuir所指出的
您將 fscanf 包含在您的定時序列中。 這將花費大部分時間。 對 function 的多次調用而不是一次調用計時總是一個好主意。
除此之外,您可以嘗試不同的方法來評估二項式系數:
double binomial(long n, long k)
{
double result = 1.0;
if ( k > n/2 )
k = n - k;
++n;
for (int i = 1; i <= k; ++i)
result *= (double)(n - i) / i;
return result;
}
這樣計算(如果我得到正確的話)減少到
for(int i = n; i <= N; i++)
{
p_value += binomial(e, i) * binomial(E - e, N - i);
}
p_value /= binomial(E, N);
可在這里測試。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.