最外面的for循环不能按预期工作

时间:2013-11-18 20:07:26

标签: c gcc ubuntu-12.04

我一直在使用UCCntu 12.04 LTS和GCC编译我的作业代码一段时间。但是,最近我遇到了两个问题如下:

  1. 以下代码使用第二个公式计算非零值的零。
  2. 从0到5或更大的标准偏差计算标准正态分布的积分时会出现大量误差。
  3. 如何解决这些问题?我特别着迷于第一个。任何帮助或建议表示赞赏。提前致谢。

    代码如下:

    #include <stdio.h>
    #include <math.h>
    #include <limits.h>
    #include <stdlib.h>
    #define N 599
    long double
    factorial(long double n)
    {
        //Here s is the free parameter which is increased by one in each step and
        //pro is the initial product and by setting pro to be 0 we also cover the
        //case of zero factorial.
        int s = 1;
        long double pro = 1;
        //Here pro stands for product.
        if (n < 0)
            printf("Factorial is not defined for a negative number \n");
        else {
        while (n >= s) { 
        pro *= s;
        s++;
        }
        return pro;
        }
    }
    int main()
    {
        // Since the function given is the standard normal distribution
        // probability density function we have mean = 0 and variance = 1.
        // Hence we also have z = x; while dealing with only positive values of 
        // x and keeping in mind that the PDF is symmetric around the mean.
        long double * summand1 = malloc(N * sizeof(long double));
        long double * summand2 = malloc(N * sizeof(long double));
        int p = 0, k, z[5] = {0, 3, 5, 10, 20};
        long double sum1[5] = {0}, sum2[5] =  {0} , factor = 1.0;
        for (p = 0; p <= 4; p++)
        {
            for (k = 0; k <=  N; k++)
            {
                summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z[p], 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k)); 
                sum1[p] += summand1[k];
            }
            //Wolfamalpha site gives the same value here
    
            for (k = 0; k <=  N; k++)
            {
                factor *= (2 * k + 1);
                summand2[k] = ((1 / sqrtl(M_PI * 2) ) * powl(z[p], 2 * k + 1) / factor);
                //printf("%Le \n", factor);
                sum2[p] += summand2[k];
            }
            sum2[p] = sum2[p] * expl((-powl(z[p],2)) / 2);
        }
        for (p = 0; p < 4; p++)
        {
        printf("The sum obtained for z between %d - %d \
        \nusing the first formula is %Lf \n", z[p], z[p+1], sum1[p+1]);
        printf("The sum obtained for z between %d - %d \
        \nusing the second formula is %Lf \n", z[p], z[p+1], sum2[p+1]);
        }
        return 0;
    }
    

    没有最外层for循环的工作代码是

    #include <stdio.h>
    #include <math.h>
    #include <limits.h>
    #include <stdlib.h>
    #define N 1200
    long double
    factorial(long double n)
    {
        //Here s is the free parameter which is increased by one in each step and
        //pro is the initial product and by setting pro to be 0 we also cover the
        //case of zero factorial.
        int s = 1;
        long double pro = 1;
        //Here pro stands for product.
        if (n < 0)
            printf("Factorial is not defined for a negative number \n");
        else {
        while (n >= s) { 
        pro *= s;
        s++;
        }
        return pro;
        }
    }
    int main()
    {
        // Since the function given is the standard normal distribution
        // probability density function we have mean = 0 and variance = 1.
        // Hence we also have z = x; while dealing with only positive values of 
        // x and keeping in mind that the PDF is symmetric around the mean.
        long double * summand1 = malloc(N * sizeof(long double));
        long double * summand2 = malloc(N * sizeof(long double));
        int k, z = 3;
        long double sum1 = 0, sum2 = 0, pro = 1.0;
        for (k = 0; k <=  N; k++)
        {
            summand1[k] = (1 / sqrtl(M_PI * 2) )* powl(-1, k) * powl(z, 2 * k + 1) / ( factorial(k) * (2 * k + 1) * powl(2, k)); 
            sum1 += summand1[k];
        }
        //Wolfamalpha site gives the same value here
        printf("The sum obtained for z between 0-3 using the first formula is %Lf \n", sum1);
          for (k = 0; k <=  N; k++)
        {
            pro *= (2 * k + 1);
            summand2[k] = ((1 / sqrtl(M_PI * 2) * powl(z, 2 * k + 1) / pro));
            //printf("%Le \n", pro);
            sum2 += summand2[k];
        }
        sum2 = sum2 * expl((-powl(z,2)) / 2);
        printf("The sum obtained for z between 0-3 using the second formula is %Lf \n", sum2);
        return 0;
    }
    

1 个答案:

答案 0 :(得分:1)

我很确定问题是factor在外循环中没有被设置回1 ..

factor *= (2 * k + 1);(在计算sum2的循环中。)

在第二个版本中,提供的工作以z = 3

开头

然而,在第一个循环中,由于在到达z [2]时你没有在p上的迭代之间清除它,它已经是一个巨大的数字。

编辑:精确的可能帮助..

基本上你有一个巨大的数字powl(z[p], 2 * k + 1)除以另一个巨大的数字factor。巨大的浮点数会失去精确度。避免这种情况的方法是尽快进行分工。

而不是先计算powl(z[p], 2 * k + 1)并除以factor:   - (z [p] z [p] ...... * z [p])/(1 * 3 * 5 * ...(2 * k + 1))`

重新排列计算:(z [p] / 1)*(z [p] ^ 2/3)*(z [p] ^ 2/5)...(z [p] ^ 2 /(2 * K + 1))

你可以在sumand2计算和summand1

中的类似技巧中执行此操作