用C计算二维阵列的标准偏差

时间:2013-11-16 03:48:41

标签: c multidimensional-array standard-deviation

这是我的代码,它应该计算fillArray填充的随机生成数组的标准偏差。 stdDev应该计算标准偏差。 otherStats应该找到数组中最大和最小的值。到目前为止,唯一生成的是偏差为0,最小和最大。这是代码:

#include <stdio.h>
#include <stdlib.h>
#include <math.h>


float fillArray (float array[7][5]);
float printArray (float array[7][5], float deviation, float largest, float smallest);
float stdDev (float array[7][5], float deviation, float average);
float otherStats (float array[7][5], float largest, float smallest);

int main ()
{
  float deviation, average, largest, smallest; 
  float array[7][5];
  fillArray (array);
  stdDev (array, deviation, average);
  otherStats (array, largest, smallest);
  printArray (array, deviation, largest, smallest);
}

float fillArray (float array[7][5])
{
  int row, column;
  for (row = 0; row < 7; row++)
    {
      for (column = 0; column < 5; column++)
        {
          array[row][column] = (float) rand () / (float) RAND_MAX;
        }
    }
  return array[7][5];
}

float stdDev (float array[7][5], float deviation, float average)
{
  float number1, number2;
  array[7][5] = fillArray(array);
  int ROw, Col;
  for (ROw = 0; ROw < 7; ROw++)
    {
      for (Col = 0; Col < 5; Col++)
        {
          number1 = array[ROw][Col] + number1;
          average = number1 / 35;
        }
     }

      for (ROw = 0; ROw < 7; ROw++)
        {
          for (Col = 0; Col < 5; Col++)
            {
              number2 = average - array[ROw][Col];
              deviation = sqrt (number2 / 35);
            }
        }
  return deviation;
}

float otherStats (float array[7][5], float largest, float smallest)
{
  array[7][5] = fillArray(array);
  float num1, num2;             //Check which ones largest or smallest.
  int ROW, COLUMN;
  for (ROW = 0; ROW < 7; ROW++)
    {
      for (COLUMN = 0; COLUMN < 5; COLUMN++)
        {
          num1 = array[ROW][COLUMN];
          num2 = array[1][1];
          largest = num2;
          smallest = num1;
          if (num1 > num2)
            {
              largest = num1;
            }
          else
            {
              smallest = num1;
            }
        }
    }
  return largest, smallest;
}

float printArray (float array[7][5], float deviation, float largest, float 
smallest)
{
  int Row, Column;

  printf("Column #:  ");

  for (Column = 0; Column < 5; Column++)
    {
      printf ("%d     ", Column);
    }
  printf("\nRow #|________________________________\n");

  for (Row = 0; Row < 7; Row++)
    {
      printf("%d    |   ", Row);

      for (Column = 0; Column < 5; Column++)
        {
          printf ("%4.2f  ", array[Row][Column]);
        }

      printf ("\n");
    }
  printf("The standard deviation is %f, the largest is %f, the smallest is %f.\n", 
deviation, largest, smallest);
}

任何帮助弄清楚我的错误都会非常感激。它编译得很好,只是我的逻辑或某些东西搞砸了。

提前致谢。

这是输出:

Column #:  0     1     2     3     4     
Row #|________________________________
0    |   0.53  0.04  0.44  0.93  0.93  
1    |   0.72  0.28  0.74  0.64  0.35  
2    |   0.69  0.17  0.44  0.88  0.83  
3    |   0.33  0.23  0.89  0.35  0.69  
4    |   0.96  0.59  0.66  0.86  0.44  
5    |   0.92  0.40  0.81  0.68  0.91  
6    |   0.48  0.22  0.95  0.92  0.15  
The standard deviation is -0.000000, the largest is 0.000000, the smallest is 0.000000.

2 个答案:

答案 0 :(得分:4)

是你的编码问题的答案,但它 是你做错的一个例子。我当然不会期望这会引起很多关注(除了可能还有一些选票和一些尖锐的批评)。

C是一种按值传递的语言。虽然大多数人都没有轻易掌握它,但这包括所有,(数组无法承受,但即使是正确应用术语“值”也是如此)。

示例#1:值参数

这个简单的例子是为了证明传递给函数的参数的地址提供给函数的参数的地址相同。

#include <stdio.h>

int foo_one(int a, int b)
{
    printf("foo:  &a = %p, &b=%p\n", &a, &b);
    return a+b;
}

int main()
{
    int a = 1, b = 2;
    printf("main: &a = %p, &b=%p\n", &a, &b);
    foo_one(a,b);
    return 0;
}

输出(地址值因系统而异)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908

注意函数中变量的逻辑地址与main()中的变量的逻辑地址不同。 ab被推入临时存储(通常是“堆栈”,但如果没有正式的数据结构课程,您可能不知道这是什么如果你有其中一个你可能不会问这个问题)。然后进行函数调用。


示例#2:功能失调的外部参数

那你为什么要关心呢。那么,现在考虑一下:

#include <stdio.h>

void foo_two(int a, int b, int c)
{
    printf("foo:  &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    c = a + b;
}

int main()
{
    int a = 1, b = 2, c = 0;
    printf("main: &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    foo_two(a,b,c);
    printf("c = %d\n", c);
    return 0;
}

输出(地址值因系统而异)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934, &c=0x7fff5fbff930
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908, &c=0x7fff5fbff904
c = 0

刚刚发生了什么?我们在c中修改的foo_two()变量 main()中的变量。它们有不同的内存地址。我们在foo_two()中修改的那个是按值副本(示例#1中讨论的“temp”变量)。


示例#3:功能性输出参数

如果只有一种方法,我们可以直接在foo_three()中告诉main()变量的内存地址...以某种方式将 地址作为“值”传递给参数,然后用它来存储我们需要去的结果;在main::c

这是完全指针的作用。在C中,指针是保存某个特定类型的其他数据的地址的变量。如果int包含整数,则int*会保存一个可以找到int的地址。

#include <stdio.h>

void foo_three(int a, int b, int* ptr)
{
    printf("foo:  &a = %p, &b=%p, ptr=%p\n", &a, &b, ptr);
    *ptr = a + b; // note the dereference operator
}

int main()
{
    int a = 1, b = 2, c = 0;
    printf("main: &a = %p, &b=%p, &c=%p\n", &a, &b, &c);
    foo_three(a,b,&c); // note the address of c being passed
    printf("c = %d\n", c);
    return 0;
}

输出(地址值因系统而异)

main: &a = 0x7fff5fbff938, &b=0x7fff5fbff934, &c=0x7fff5fbff930
foo:  &a = 0x7fff5fbff90c, &b=0x7fff5fbff908, ptr=0x7fff5fbff930
c = 3

这很重要。仔细查看foo_three()中正在打印的内容。 ptr参数的(指针)与cmain()变量的地址相同我们可以直接修改该地址的int


<强>摘要

如果你想通过C中的地址传递某些东西,那么传递地址正是你要做的事情;传递地址并声明参数是指向变量类型的指针。在函数中使用解引用运算符向/从所述地址写入/读取数据,并且将适当地修改调用者端变量。

现在,完成所有这些后,请回顾一下您的程序,看看您是否能够理解如何将其应用于您的问题。并研究C指针。它们并不神奇,而且 严重用于大多数C程序。值得花时间尽快学习。

答案 1 :(得分:2)

我认为你是学生。学习一门新语言时,阅读其他人的代码确实很有帮助。我重写了你的均值/标准偏差函数,展示了我如何处理这种事情。 (1维不是2维...没有免费午餐!)

希望这能让你走上正轨。

我同意您需要使用调试器的其他海报......即使没有编译器错误或链接器错误,程序仍可能无法正常工作。您可以使用单元测试框架(如Google Test或CppUnit)验证函数的正确性,或者您可以使用临时测试函数,如下所示。

// tested with minGW_w32 gcc-4.7.2

#include <stdio.h>
#include <stdlib.h>
#include <math.h>

/// Calculate mean and standard deviation of a 1-dimensional array.
/// Example showing how to pass values by reference.
///
/// @param[in] x = 1-dimensional array of values to evaluate
/// @param[in] length = number of elements in array
/// @param[out] pdMean = caller-allocated storage for arithmetic mean average
/// @param[out] pdStdDev = caller-allocated storage for standard deviation
///
/// void return type because this function does not have a return value.
///
void calculateMeanAndStdDev (double x[], size_t length, double* pdStdDev, double* pdMean)
{
    size_t index;       // size_t is an unsigned integer type useful for counting array elements

    double sumX = 0;
    double sumXSquared = 0;
    for (index = 0; index < length; index++)
    {
        // accumulate sum of the x values
        sumX += x[index];

        // accumulate the sum of each x squared
        sumXSquared += ( x[index] * x[index] );
    }

    // pdMean is a pointer to the variable in the caller, which will receive the value
    // *pdMean is the object that double& pdMean points to.
    // I'm using the pd prefix to mean pointer to double.
    // I prefer to write this as (*pdMean) to help clarify that I'm using * to dereference a pointer, not to perform multiplication.
    (*pdMean) = sumX / length;

    double variance = 0;
    for (index = 0; index < length; index++)
    {
        const double differenceFromMean = x[index] - (*pdMean);
        // without the parenthesis this is written as  differenceFromMean = x[index] - *pdMean;

        variance += differenceFromMean * differenceFromMean;
    }
    (*pdStdDev) = sqrt ( variance / length);

    /// @note there's a more effient way to calculate mean and standard deviation, where you accumulate sumX and sumXSquared in a single pass,
    /// then mean is sumX / length and StdDev is calculated from sumXsquared and (sumX)*(sumX).
    /// For purposes of this exercise I stuck with the more direct equation.
}

/// Example ad hoc test driver calling calculateMeanAndStdDev()
void Test_calculateMeanAndStdDev()
{
    double demoArray[] = { 1.0, 2.0, 3.0, 7.5, 9.2 };
    const double expect_Mean = 4.54;
    const double expect_StdDev = 3.2196894260161177;

    double Mean; // will be filled in by calculateMeanAndStdDev
    double StdDev; // will be filled in by calculateMeanAndStdDev
    calculateMeanAndStdDev(demoArray, sizeof(demoArray)/sizeof(double), &StdDev, &Mean);

    const double compare_threshold = 0.001;
    if ( abs(Mean - expect_Mean) > compare_threshold ) {
        printf("\n""Test_calculateMeanAndStdDev() fail: Mean=%1.6f buf expect_Mean=%1.6f", Mean, expect_Mean);
    } else {
        printf("\n""Test_calculateMeanAndStdDev(): Mean=%1.6f as expected", Mean);
    }
    if ( abs(StdDev - expect_StdDev) > compare_threshold ) {
        printf("\n""Test_calculateMeanAndStdDev() fail: StdDev=%1.6f buf expect_StdDev=%1.6f", StdDev, expect_StdDev);
    } else {
        printf("\n""Test_calculateMeanAndStdDev(): StdDev=%1.6f as expected", StdDev);
    }
}

int main(void)
{
    Test_calculateMeanAndStdDev();
    return 0;
}

C指针非常强大且是语言的基础,但它们也是最难理解的功能之一。这就是为什么像Java这样的语言会从程序员那里隐藏这个指针机制。在C语言中,你必须进行防御性编程,因为编译器总是假设你知道你在做什么。想要编写在执行期间修改自身的代码吗?即使您的程序自行杀死,C也可以。写在堆栈上分配的数组范围之外?当然,没问题,你的功能只是无法返回...总而言之,在处理指针时,特别是在第一次启动时,代码防御性地试图避免混淆。因为您不能依赖编译器警告来告诉您是否会出现问题。