简体   繁体   中英

calculate moving average of an static array in c

I wrote this code to calculate moving average of array in c.

Array_MovingAverage(const int inputSeries[], 
                    size_t inputSize, 
                    size_t window, 
                    float output[],
                    size_t outputSize) {
  if (inputSeries && output != NULL){
    for(size_t i = 0; i < window ; i++)
      if (window < inputSize)
        if (inputSeries != NULL && output != NULL) {
          if(outputSize >= inputSize) {
            size_t inputSize[11] =  {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1};
            const uint8_t window = 5;
            {
              const int inputSeries[] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2,1};

              double window = 5;
              double c = 2.0;
              double d = 2.0;

              for(int i = 0; i < window; i++)
              {
                c += inputSeries[i];
                d = c / window;
              }

              return true;
            }
          }
        }
    }
  }

I've been trying to calculate moving average of an array in C and get an desired output but it seems it doesn´t work. Can you please give me an advice how can I calculate moving average of an static array in C?

Output should be:

Moving Average: 1 2 2 3 6 8 9 2 1 2 1
                0 0 0 0 3 4 6 6 5 4 3

Let's start from scratch. Your attempt to adapt this code is only making it very unclear what you are trying to do, and the original code appears to be flawed in any case. Going through the issues with the code is probably unproductive.

Firstly for a moving average N you keep a sum of the last N values, and for each new sample, you:

  1. add sample[n] to sum
  2. subtract sample[nN] from sum
  3. output sum / N

Taking your interface, but omitting the redundant outputSize - output is the same size as the input), an implementation might look like:

void Array_MovingAverage( const int* inputSeries, 
                          size_t inputSize, 
                          size_t window, 
                          float* output ) 
{
    int sum = 0 ;

    if( inputSeries != NULL && output != 0 )
    {
        for( size_t i = 0; i < inputSize; i++ )
        {
            // Add newest sample
            sum += inputSeries[i] ;
            
            // Subtract oldest sample
            if( i >= window )
            {
                sum -= inputSeries[i - window] ;
            }
            
            output[i] = (float)sum / window ;
        }
    }
}

To use it, you might have:

int main()
{
    const int input[] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1};
    const size_t size = sizeof(input) / sizeof(*input) ;
    float output[size] ;
    
    Array_MovingAverage( input, size, 5, output ) ;
    
    for( size_t i = 0; i < size; i++ )
    {
        printf( "%.2f\n", output[i]) ;
    }

    return 0;
}

For your sample data {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1} , the output is:

{0.20, 0.60, 1.00, 1.60, 2.80, 4.20, 5.60, 5.60, 5.20, 4.40, 3.00}

在此处输入图像描述

Now it is not clear from your question, but form other comments it seems you wish to hack this function to ignore the input provided by the caller because you cannot modify the caller. Frankly that is bizarre, but here is a "safe" way of doing that. Let's assume the outputSize will be reinstated, because clearly you will need that to avoid overrunning the callers output buffer. The simplest solution is to wrap the whole body of the function is an additional shell of braces {...} allowing you to create shadow variables overriding the input parameters leaving the rest of the code untouched:

void Array_MovingAverage( const int* inputSeries, 
                          size_t inputSize, 
                          size_t window, 
                          float* output,
                          size_t outputSize ) 
{
    // Prevent unused warnings
    (void)inputSeries ;
    (void)inputSize ;
    (void)window ;

    // Create block to allow variables to be "shadowed"
    {
        // Override inputs
        // NASTY HACK
        const size_t inputSize = 11 ;
        const int inputSeries[11] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1};
        const size_t window = 5 ;
        
        int sum = 0 ;
    
        if( inputSeries != NULL && output != 0 )
        {
            for( size_t i = 0; i < inputSize; i++ )
            {
                // Add newest sample
                sum += inputSeries[i] ;
                
                // Subtract oldest sample
                if( i >= window )
                {
                    sum -= inputSeries[i - window] ;
                }
                
                // Only write to caller output if index in bounds
                if( i < outputSize )
                {
                    output[i] = (float)sum / window ;
                }
            }
        }
    }
}

Of course you could simply change the variable names and ignore the input parameters, but if doing this in existing working code of any complexity, the above hack may be less error prone (no renaming of variables). That said, such a solution might look like:

void Array_MovingAverage( const int* inputSeries, 
                          size_t inputSize, 
                          size_t window, 
                          float* output,
                          size_t outputSize ) 
{
    // Prevent unused warnings
    (void)inputSeries ;
    (void)inputSize ;
    (void)window ;

    // Local "input" data
    const int input[] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1};
    const size_t size = sizeof(input) / sizeof(*input) ;
    const size_t width = 5 ;
 
    int sum = 0 ;

    if( input != NULL && output != 0 )
    {
        for( size_t i = 0; i < size; i++ )
        {
            // Add newest sample
            sum += input[i] ;
            
            // Subtract oldest sample
            if( i >= window )
            {
                sum -= input[i - width] ;
            }
            
            // Only write to caller output if index in bounds
            if( i < outputSize )
            {
                output[i] = (float)sum / window ;
            }
        }
    }
}

You have lots of issues in your code:

Array_MovingAverage(const int inputSeries[], size_t inputSize, size_t window, float output[],
                        size_t outputSize) {
 if (inputSeries && output != NULL){
   for(size_t i = 0; i < window ; i++)
     if (window < inputSize)
       if (inputSeries != NULL && output != NULL) {  << This is same as if statemend 3 lines above
         if(outputSize >= inputSize) {
           size_t inputSize[11] =  {1, 2, 2, 3, 6, 8, 9, 2, 1, 2, 1}; //<< this hides parameter. And has totally different type.
           const uint8_t window = 5; // Also hiding parameter
           {
             const int inputSeries[] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2,1}; // again hiding

             double window = 5;  // more hiding of variables and parameters
             double c = 2.0; // Where does this value come from?
             double d = 2.0;

             for(int i = 0; i < window; i++) // Same loop variable as outer loop.
             {
               c += inputSeries[i];
               d = c / window;
             }

             return true;  // You return after first iteration of outer loop.
// No printf so far
// No value assigned to output[] so far.
// The only result is return value true.
           }
         }
       }
   }
 }

You hide window two times with different types. Unless that is some obfuscation contest, that is a NO NO. Also the other parameters are hidden with variables of different type.

The outer loop has no effect at all, as it will never reach second iteration.

Checking parameters inside the loop again and again (if it was executed more than once) is waste of CPU time.

Lets reorder your code a bit and remove some strange things (code not tested, whoever finds typos, may keep them. ;) )

void Array_MovingAverage(const int inputSeries[], size_t inputSize, size_t window, float output[],
                         size_t outputSize) {
   if ( window < inputSize
     && inputSeries != NULL && output != NULL
     && outputSize >= inputSize ) {

      double c = 0.0;
      double avg;
      int i;

      // first fill partial window at begin
      for (int i = 0; i < window; i++)
      {
         c += inputSeries[i];
         avg = c / (i+1);
         output[i] = avg;
      }

      // Then handle full windows until we reach the end
      // c now contains sum of entries 0..window-1
      // i points to entry 'window'
      for ( ; i < inputSize; i++)
      {
         // Move the window by adding 1 new element and remove 1 old element
         c += inputSeries[i];
         c -= inputSeries[i-window]
         avg = c / window;
         output[i] = avg;
      }
   }
}

int main(void)
{
   int    input[] = {1, 2, 2, 3, 6, 8, 9, 2, 1, 2,1};
   size_t Size = sizeof(input)/(input[0]);
   float  output[Size] = {0};

   Array_MovingAverage(intput, Size, 5, output, Size);

   printf("Moving avarage:\n");
   for (int i = 0; i < Size; i++)
   {
      printf("%d ", input[i]);
   }

   for (int i = 0; i < Size; i++)
   {
      printf("%f ", (int)(output[i]+0.5));
   }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM