How to optimise an image pixelation program - c

I have written some serial code which I would like to optimise as much as possible before I parallelise it using OpenMP. The program reads in a PPM file by iterating through the pixel data in 4x4 cells (variable c), then it finds the average RGB value of each of those 4x4 cells, and then finally writes to a new file by outputing the average colour value, again of each of the 4x4 cells. This creates a sort of mosaic/pixelation effect.
Having performance profiled my code, the main bottlenecks are fscanf and fprintf. I am ignoring execution time to read/write to disk, so these two functions do not matter.
My effort to optimise so far:
Loop jamming: There are two nested FOR loops within the code which have the exact same loop conditions. However, the second set of nested FOR loops requires that the functions needed to calculate the average RGB value are kept outside of that specific set. The average RGB value calculations are then needed for use in the third set of nested FOR loops (which have the same loop conditions as the second set). Because of this, I have struggled to combine the second and third sets of nested FOR loops despite their similarity.
Loop invariant computations: I have tried to move certain operations outside of the loop where possible, but this has proven to be difficult.
To summarise: How can I optimise this program to reduce the execution time as much as possible?
My code:
typedef struct { //struct holding RGB type int
int r, g, b; //12 bytes
} pixelInt;
typedef struct { //struct holding RGB type unsigned char
unsigned char r, g, b; //3 bytes
} pixel;
int c = 4; // Variable of 4x4 grids
int width, height; //image variable declarations
//Raw 1 dimensional store of pixel data - will contain all the data for each pixel in the image
pixel *data = (pixel *)calloc(width * height, sizeof(pixelInt));
//Loop through entire input image
for (int yy = 0; yy < height; yy += c)
{
for (int xx = 0; xx < width; xx += c)
{
//the total colour of cell of size 'c'
pixelInt cell_tot = { 0, 0, 0 }; //zero initialize struct containing mosaic cell pixel totals.
unsigned int counter = 0; //the counter for how many pixels are in a 4x4 cell
int bx = xx + c; //used in loop conditions
int by = yy + c;
// Store each color from the cell into cell_tot struct
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
unsigned char r, g, b; //maximum vales are 255, i.e. unsigned char data type
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b); //%hhu is unsigned char specifier
//store the pixel value into data array
data[index_1d].r = r;
data[index_1d].g = g;
data[index_1d].b = b;
counter++; //increment counter
//average pixel color of cell
cell_tot.r += r;
cell_tot.g += g;
cell_tot.b += b;
}
}
//average colour of cell found by dividing cell total by loop counter
pixel cell_average;
cell_average.r = cell_tot.r / counter;
cell_average.g = cell_tot.g / counter;
cell_average.b = cell_tot.b / counter;
//Loop through the new image in cells of size c
for (int y = yy; y < by; y++)
{
for (int x = xx; x < bx; x++)
{
unsigned int index_1d = x + y * width; //calculate 1d index from x-index (x), y-index(y) and width;
//Assign average cell value to the pixels in the cell
data[index_1d].r = cell_average.r;
data[index_1d].g = cell_average.g;
data[index_1d].b = cell_average.b;
//Output the average colour value for the image
fprintf(f_output, "%hhu %hhu %hhu \t", data[index_1d].r, data[index_1d].g, data[index_1d].b);
}
fprintf(f_output, "\n"); //Prints new line
}
}
}

On a 1024x1024 image on my machine your code executes in 0.325s. The following code executes in 0.182s:
unsigned w = width/c, h = height/c;
unsigned *accum = (unsigned*)malloc(3*sizeof(unsigned)*w);
char *line = (char*)malloc(12*w);
unsigned denom = c*c;
//Loop through entire input image
for (int yy = 0; yy < h; ++yy)
{
memset(accum, 0, 3*sizeof(unsigned)*w);
// read and accumulate c lines
for(int y = 0; y < c; ++y)
{
for (int xx = 0; xx < w; ++xx)
{
for (int x = 0; x < c; ++x)
{
unsigned char r, g, b;
fscanf(f, "%hhu %hhu %hhu", &r, &g, &b);
accum[3*xx+0] += r;
accum[3*xx+1] += g;
accum[3*xx+2] += b;
}
}
}
// format a line
for(int xx = 0; xx < w; ++xx)
{
char *cell = line + 12*c*xx;
snprintf(cell, 12, "%3u%4u%4u", accum[3*xx]/denom, accum[3*xx+1]/denom, accum[3*xx+2]/denom);
cell[11] = '\t';
for(int x = 1; x < c; ++x)
memcpy(cell + 12*x, cell, 12);
}
// write it out times c
line[12*w-1] = '\n';
for(int y = 0; y < c; ++y)
fwrite(line, 12*w, 1, f_output);
}
The trick here is to format the averaged values only once and then duplicate the formatted strings. Also by acting on one row at a time I have better chances of utilizing the memory caches.
To go beyond that you would need to re-implement the fscanf to parse the integers faster.

Related

C Code for numerical integration works on one computer but blows up on another [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
I have written a code for a simple pendulum with numerical integration using rk4 method. Here's an image of expected result.
It works on my laptop, running Ubuntu 14.04, 64 bit, (it gives a sine wave as the result), but doesn't work on my PC, which runs Debian 8 and is also 64 bit.
Here's an image of the wrong plot.
Any reason why this would be happening?
Here's the code:
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
int N = 2;
float h = 0.001;
struct t_y_couple {
float t;
float *y;
};
struct t_y_couple integrator_rk4(float dt, float t, float *p1);
void oscnetwork_opt(float t, float *y, float *dydt);
int main(void) {
/* initializations*/
struct t_y_couple t_y;
int i, iter, j;
// time span for which to run simulation
int tspan = 20;
// total number of time iterations = tspan*step_size
int tot_time = (int)ceil(tspan / h);
// Time array
float T[tot_time];
// pointer definitions
float *p, *q;
// vector to hold values for each differential variable for all time
// iterations
float Y[tot_time][2];
// N = total number of coupled differential equations to solve
// initial conditions vector for time = 0
Y[0][0] = 0;
Y[0][1] = 3.14;
// set the time array
T[0] = 0;
// This loop calls the RK4 code
for (i = 0; i < tot_time - 1; i++) {
p = &Y[i][0]; // current time
q = &Y[i + 1][0]; // next time step
// printf("\n\n");
// for (j=0;j<N;j++)
// call the RK4 integrator with current time value, and current
// values of voltage
t_y = integrator_rk4(h, T[i], p);
// Return the time output of integrator into the next iteration of time
T[i + 1] = t_y.t;
// copy the output of the integrator into the next iteration of voltage
q = memcpy(q, t_y.y, (2) * sizeof(float));
printf("%f ", T[i + 1]);
for (iter = 0; iter < N; iter++)
printf("%f ", *(p + iter));
printf("\n");
}
return 0;
}
struct t_y_couple integrator_rk4(float dt, float t, float y[2]) {
// initialize all the pointers
float y1[2], y2[2], y3[2], yout[2];
float tout, dt_half;
float k1[2], k2[2], k3[2], k4[2];
// initialize iterator
int i;
struct t_y_couple ty1;
tout = t + dt;
dt_half = 0.5 * dt;
float addition[2];
// return the differential array into k1
oscnetwork_opt(t, y, k1);
// multiply the array k1 by dt_half
for (i = 0; i < 2; i++)
y1[i] = y[i] + (k1[i]) * dt_half;
// add k1 to each element of the array y
// do the same thing 3 times
oscnetwork_opt(t + dt_half, y1, k2);
for (i = 0; i < 2; i++)
y2[i] = y[i] + (k2[i]) * dt_half;
oscnetwork_opt(t + dt_half, y2, k3);
for (i = 0; i < 2; i++)
y3[i] = y[i] + (k3[i]) * dt_half;
oscnetwork_opt(tout, y3, k4);
// Make the final additions with k1,k2,k3 and k4 according to the RK4 code
for (i = 0; i < 2; i++) {
addition[i] = ((k1[i]) + (k2[i]) * 2 + (k3[i]) * 2 + (k4[i])) * dt / 6;
}
// add this to the original array
for (i = 0; i < 2; i++)
yout[i] = y[i] + addition[i];
// return a struct with the current time and the updated voltage array
ty1.t = tout;
ty1.y = yout;
return ty1;
}
// function to return the vector with coupled differential variables for each
// time iteration
void oscnetwork_opt(float t, float y[2], float *dydt) {
int i;
dydt[0] = y[1];
dydt[1] = -(1) * sin(y[0]);
}
You have a problem of lifetime with your variable yout in integrator_rk4(). You assign address of yout to ty1.y but you use it outside this function. This is undefined behavior.
quick fix:
struct t_y_couple {
float t;
float y[2];
};
struct t_y_couple integrator_rk4(float dt, float t, float y[2]) {
float y1[2], y2[2], y3[2], yout[2];
// ...
ty1.t = tout;
ty1.y[0] = yout[0];
ty1.y[1] = yout[1];
return ty1;
}
You have a lot of useless allocation and you made "spaghetti code" with your global variable. You should not cast the return of malloc.

how to change the value stored in a VLA which is in a struct

I have the following structure im using to encode a PPM file with a message using steganography:
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
and the color:
typedef struct{
unsigned char red, green, blue;
} COLOR;
and method:
PPM *encode(char *text, PPM *img){
//tested
printf("entered encode\n");
PPM *newPPM;
newPPM = duplicate(img);
printf("duplicated ppm\n");
int x,y, currentChar, textLength;
textLength = strlen(text);
////
for(currentChar = x = y = 0; currentChar < textLength; currentChar++){
printf("the current character is %c\n", *(text+currentChar));
//between 1 and the width
x += (rand() % (newPPM->width -1)) + 1;
printf("generated %d for x\n",x);
if(x >= newPPM->width){
printf("%d is greater than width(%d)\n",x,newPPM->width);
x -= newPPM->width;
printf("%d is the new x\n", x);
y++;
printf("incremented y to be %d\n", y);
}
newPPM->colorValues[y][x].red = text[currentChar]; //error (1)
printf("changed the value of color[%d][%d].red, to be %d, which is %c\n",y,x, text[currentChar], text[currentChar]);
}
return newPPM;
}
How do you access for example "red" within the pointer to the 1d array seen at (1)?
Edit: I get the error message:
"error: invalid use of array with unspecified bounds
newPPM->colorValues[y][x].red = text[currentChar];"
Edit 2: I'm hearing that I cannot access the elements of colorValues in
typedef struct{
char code[CODE_LENGTH];
COMMENT *commentPPM;
int width, height, max;
COLOR (*colorValues)[];
} PPM;
as it hasn't got the width specified so i cant determine the offset. However I this is just a pointer to a flexible array member is getting assigned a type
ppmFile->colorValues = getColors(fd, ppmFile->width, ppmFile->height);
COLOR (*getColors(FILE *fd, int width, int height))[]{
COLOR (*colors)[width] = (COLOR(*)[width]) malloc(sizeof(COLOR[height][width]));
int i,j;
for(i = 0; i < height; i++) {
for(j = 0; j < width; j++) {
fscanf(fd,"%d %d %d", &colors[i][j].red, &colors[i][j].green, &colors[i][j].blue);
}
}
return colors;
}
which has got the width specified. So if I'm understanding correct when I am passing this back to be stored in the struct i am "losing" the offset (width). However When I am in the encrypt method, I have access to the width, height, and current x and y positions, surely there is a way of telling the compiler that this flexible array member has the offset of width,I did do this in the printColors method and it worked fine (see bellow), why cant I tell the compiler that the values stored in newPPM->colorValues have the offset of width?
void printColors(int width, int height, COLOR (*colors)[width]){
int n, j;
for(n = 0; n < height; n++) {
for(j = 0; j < width; j++) {
printf("%d %d %d\n", colors[n][j].red, colors[n][j].green, colors[n][j].blue);
}
}
}
is there a way of casting the newPPM->colorValues to tell it to have the offset width? Like I did with colors in printColors
You're probably getting an error like:
prog.c:10:14: error: subscript of pointer to incomplete type 'struct foo []'
thing->foos[0][0].bar;
~~~~~~~~~~~^
1 error generated.
For reference, the above is the output of compiling this code:
struct foo { int bar; };
struct baz {
struct foo (*foos)[];
};
int main () {
struct baz * thing;
thing->foos[0][0].bar;
return 0;
}
(Live)
What the compiler is trying to tell you is that it cannot compute the offset needed to access subsequent elements of the outer array. The reason is that it doesn't know the size of the array elements (as they're of incomplete type, that is lacking size information).
Basically, it's trying to compute (the following is a pseudo language, not C)
thing + offset(foos) + 0 * sizeof(struct foo[]) + 0 * sizeof(struct foo) + offset(bar)
but it can't because it doesn't know sizeof(struct foo[]).
The root of this issue is that your trying to have a pointer to a variable length array in the first place. Changing the member to
struct foo (*foos)[42];
"solves" this by giving the arrays dome size.
If you want a 2D array just make it 1D, appending all inner arrays. (Of course this works only if they're of the same size, i.e. if you want a rectangular 2D array)
struct foo * grid = malloc (sizeof (struct foo) * rows * columns);
// access using grid [c * rows + r]
You can access 2D data in a 1D array by calculating the array index formula yourself.
buf[ width*y + x ];
where width needs to be the stride in units of the buffer type.

Getting the 0-255 values from a pixel in a ppm file C

Ok, so I have code that will read in the header from a ppm image, allocate memory for the size of the image, and will successfully print the blank spots (a random number repeated in terminal) for each pixel. All I need to know is how I am supposed to read in the red green and blue values (the 3 separate values ranging from 0-255) for each pixel. I don't know how to access this data within each pixel. Here is my code so far:
#include <stdio.h>
#include <stdlib.h>
int subscript(int row,int column,int numberColumns);
int sub(int rd, int gr, int bl);
//table of contents for the subscript
int main(void){
char header[5];
scanf("%s",header);
printf("%s",header);
printf("\n");
int width, height, depth;
scanf("%d %d %d\n", &width, &height, &depth);
printf("%d %d %d\n", width, height, depth);
int red = 0;
int green = 0;
int blue = 0;
int sm;
int r = 0;
int c = 0;
//allocate memory for bit to be used throughout main
unsigned char *bit = malloc(width*height);
int *rgb = malloc(3*depth);
//loops to read in table and print it
while(r < height){
while(c < width)
{
int col;
scanf("%d",&col);
//brings in allocated memory and values
bit[subscript(r,c,width)] = col;
int clr;
rgb[sub(red,green,blue)] = clr;
int color = clr + col;
printf(" %d",clr);
c=c+1;
}
printf("\n");
r = r + 1;
c = 0;
}
free(bit);
}
int subscript(int row,int column, int numberColumns)
{
return row * numberColumns + column;
//retuns items for subscript
}
int sub(int rd, int gr, int bl)
{
return rd+gr+bl;
}
PPM files store colours as triples of bytes (one byte each for r, g, and b in that order) if the maximum colour value field in the header is less than 256 and triples of two bytes if it is 256 or greater (so two bytes for each of r, g, and b, again in that order).
In the two bytes per channel case, the bytes are MSB first (big-endian).
scanf("%c", &byte_var); will read you a single character (byte) into byte_var, which should be an appropriate type. You can then process it accordingly. scanf("%hhu", &byte_var); will read an unsigned character if you are using C99 - if you are using C89 you should look up getchar.
Now, scanf returns the number of successfully converted arguments or EOF, so you should be checking the result for both incorrect input and the end of input.
For example:
int n;
char c;
while ((n = scanf("%c", &c)) != EOF && 1 == n) {
// do something
}
An example use of this would be:
// Read width, height, work out how many bytes you need per pixel.
...
// Now read some pixels
// Here I assume one byte per pixel; this would be a good situation
// to use a function for reading different channel widths
w = 0, h = 0;
while ((n = scanf("%hhu%hhu%hhu", &r, &g, &b)) != EOF && 3 == n
&& w < width && h < height) {
// now do something with r, g, b
// e.g. store them in an appropriate pixels array at pixels[w][h]
...
++w;
if (w == width) {
w = 0, ++h;
}
}
I also see you are reading from stdin, which I find a bit unusual since the title indicates you are working with a file. You can open a file with fopen (don't forget to check the result), use fscanf to read from it, and use fclose to close it afterwards.
However, I suggest reading the whole file into memory and processing it there, because reading a file a few bytes at a time is slow.
Last, I note that you are only allocating width * height bytes for bit when you need bytes_per_channel * num_channels * width * height, not checking whether your malloc failed, not freeing rgb. You should fix these things.

Flipping Vertices with C

I am trying to flip an image in C vertically so if the image is < it will end up > and my function includes
//Setting the struct up for the pixel's
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pxiels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width, height;
int maxColor = 255;
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType imgur)
{
int x,y;
const int middle = imgur.width / 2;
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
for(x=0; x < middle; ++x)
{
tmp = p[x];
p[x] = p[imgur.width - 1 - x];
p[imgur.width - 1 - x] = tmp;
}
}
}
I got my structs to work but for some reason my function will not output it, I am scanning in the image into from a struct so....
//Scanning in the pixels for the first image
for(i=imageA.height-1; i <= 0; i--)
{
for(j=0; j < imageA.width; j++)
{
scanf("%hhu", &imageA.image[i][j].red);
scanf("%hhu", &imageA.image[i][j].green);
scanf("%hhu", &imageA.image[i][j].blue);
}
}
What am I doing wrong in my function?
It should be
for(x=0; x < width; x++)
{
for(y = 0; y < height/2; y++)
{
temp = imgur.image[x][y];
imgur.image[x][y] = imgur.image[x][height-y-1]
imgur.image[x][height-y-1] = temp;
}
}
}
Shouldn't this: for(i=imageA.height-1; i <= 0; i--) be for(i=imageA.height-1; i >= 0; i--)? (in the "scanning in the pixels for the first image" code)
I imagine your compiler must be complaining about
struct pixel tmp;
struct *pixel p;
for(y=0; y < imgur.height; ++y)
{
p = tmp + y * imgur.width;
You are adding a struct to an int and allocating the result to a pointer. How is it supposed to work?
EDIT now that you have updated your question with "better" code and it's still not working, here are a few things you could / should change.
You declare a variable tmp then try to access temp. Recipe for failure
You pass the entire struct imgur to the function. That means "make a copy of everything". You should really pass a pointer to the object - change the prototype to reflect that, and access the elements as imgur->height etc
You never declare the variables height and width in your MirrorVertical function
(minor) you compute the value height - 1 - y twice per inner loop - 20000 times in total. If you swap the inner and outer loops and compute it just once (and assign to a new variable newY) you can save a little bit of time (not sure it it's really more efficient since you end up looping over X which might destroy cache coherence instead, especially with big images).
My compiler (and the C standard) complains about the statement int maxColor = 256; in the definition of the struct; you cannot initialize a value in the typedef.
Miscellaneous other errors thrown by the compiler.
I took the liberty of fixing many of them - that leads to the following code which appears to compile and run; now all you need is add your "input image" and "output image" functions (maybe).
#include <stdio.h>
//Setting the struct up for the pixels
struct pixel
{
unsigned char red;
unsigned char green;
unsigned char blue;
};
//Setting the struct up for the Image Type and scanning in the pixels into an array
struct ImageType
{
char ppImage[3];
char comment[256];
char newlinechar;
int width;
int height;
int maxColor; // cannot initialize this here; removed "=256"
struct pixel image[100][100];
};
//Function in order to flip the image, going from the left most pixel flipping with the right most
void MirrorVertical(struct ImageType *imgur) // using a pointer to the struct
{
int x,y, height, width; // added declaration of height, width
// const int middle = imgur->width / 2; // removed, not used
struct pixel tmp; // use same name here and in loop
height = imgur->height; // initialize once - save a redirect later
width = imgur->width; // ditto
for(y = 0; y < imgur->height/2; y++) // made this the outer loop
{
int newY = height - y - 1; // so we only compute it once
for(x=0; x < imgur->width; x++)
{
tmp = imgur->image[x][y]; // use "tmp" not "temp"
imgur->image[x][y] = imgur->image[x][newY];
imgur->image[x][newY] = tmp;
}
}
}
// a simple main program… this doesn't really do anything except call the function
int main(void) {
struct ImageType i1;
// … need to add code to import the image
MirrorVertical(&i1); // note - passing POINTER to i1, not the entire struct
// … need to add code to export the image
}
Let me know if that works.

Selecting and analysing window of points in an array

Could someone please advise me on how to resolve this problem.
I have a function which performs a simple regression analysis on a sets of point contained in an array.
I have one array (pval) which contains all the data I want to perform regression analysis on.
This is how I want to implement this.
I get an average value for the first 7 elements of the array. This is what I call a 'ref_avg' in the programme.
I want to perform a regression analysis for every five elements of the array taking the first element of this array as the 'ref_avg'. That is in every step of the regression analysis I will have 6 points in the array.
e.g
For the 1st step the ref_avg as calculated below is 70.78. So the 1st step in the simple regression will contain these points
1st = {70.78,76.26,69.17,68.68,71.49,73.08},
The second step will contain the ref_avg as the 1st element and other elements starting from the second element in the original array
2nd = {70.78,69.17,68.68,71.49,73.08,72.99},
3rd = {70.78,68.68,71.49,73.08,72.99,70.36},
4th = {70.78,71.49,73.08,72.99,70.36,57.82} and so on until the end.
The regression function is also shown below.
I don't understand why the first 3 elements of the 'calcul' array have value 0.00 on the first step of the regression, 2 elements on the 2nd step,1 elements on the 3rd.
Also the last step of the regression function is printed 3 times.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
float pval[]={76.26,69.17,68.68,71.49,73.08,72.99,70.36,57.82,58.98,69.71,70.43,77.53,80.77,70.30,70.5,70.79,75.58,76.88,80.20,77.69,80.80,70.5,85.27,75.25};
int count,Nhour;
const int MAX_HOUR = 24;
float *calcul=NULL;
float *tab_time =NULL;
float ref_avg;
int size_hour=7;
float sum=0;
int length = Nhour+1;
float m;
float b;
calcul=(float*)calloc(MAX_HOUR,sizeof(calcul));
if (calcul==NULL)
{
printf(" error in buffer\n");
exit(EXIT_FAILURE);
}
tab_time= calloc(MAX_HOUR,sizeof(float));
/* Get the average of the first seven elements */
int i;
for (i=0;i<size_hour;i++)
{
sum += pval[i];
}
ref_avg = sum / size_hour;
count=0;
/* perform the regression analysis on 5 hours increment */
while(count<=MAX_HOUR)
{
++count;
Nhour=5;
int pass = -(Nhour-1);
int i=0;
for(i=0;i<Nhour+1;i++)
{
if(count<MAX_HOUR)
{
calcul[0]=ref_avg;
calcul[i] =pval[count+pass];
pass++;
}
printf("calc=%.2f\n",calcul[i]); // For debug only
tab_time[i]=i+1;
if(i==Nhour)
{
linear_regression(tab_time, calcul, length, &m, &b);
printf("Slope= %.2f\n", m);
}
}
}
free(calcul);
calcul=NULL;
free(tab_time);
tab_time=NULL;
return 0;
}
/* end of the main function */
/* This function is used to calculate the linear
regression as it was called above in the main function.
It compiles and runs very well, was just included for the
compilation and execution of the main function above where I have a problem. */
int linear_regression(const float *x, const float *y, const int n, float *beta1, float *beta0)
{
float sumx = 0,
sumy = 0,
sumx2 = 0,
sumxy = 0;
int i;
if (n <= 1) {
*beta1 = 0;
*beta0= 0;
printf("Not enough data for regression \n");
}
else
{
float variance;
for (i = 0; i < n; i++)
{
sumx += x[i];
sumy += y[i];
sumx2 += (x[i] * x[i]);
sumxy += (x[i] * y[i]);
}
variance = (sumx2 - ((sumx * sumx) / n));
if ( variance != 0) {
*beta1 = (sumxy - ((sumx * sumy) / n)) / variance;
*beta0 = (sumy - ((*beta1) * sumx)) / n;
}
else
{
*beta1 = 0;
*beta0 = 0;
}
}
return 0;
}
I think this code produces sane answers. The reference average quoted in the question seems to be wrong. The memory allocation is not needed. The value of MAX_HOUR was 24 but there were only 23 data values in the array. The indexing in building up the array to be regressed was bogus, referencing negative indexes in the pval array (and hence leading to erroneous results). The variable Nhour was referenced before it was initialized; the variable length was not correctly set. There wasn't good diagnostic printing.
The body of main() here is substantially rewritten; the editing on linear_regression() is much more nearly minimal. The code is more consistently laid out and white space has been used to make it easier to read. This version terminates the regression when there is no longer enough data left to fill the array with 5 values - it is not clear what the intended termination condition was.
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void linear_regression(const float *x, const float *y, const int n,
float *beta1, float *beta0);
int main(void)
{
float pval[]={
76.26, 68.68, 71.49, 73.08, 72.99, 70.36, 57.82, 58.98,
69.71, 70.43, 77.53, 80.77, 70.30, 70.50, 70.79, 75.58,
76.88, 80.20, 77.69, 80.80, 70.50, 85.27, 75.25,
};
const int Nhour = 5;
const int MAX_HOUR = sizeof(pval)/sizeof(pval[0]);
const int size_hour = 7;
float ref_avg;
float sum = 0.0;
float m;
float b;
float calc_y[6];
float calc_x[6];
/* Get the average of the first seven elements */
for (int i = 0; i < size_hour; i++)
sum += pval[i];
ref_avg = sum / size_hour;
printf("ref avg = %5.2f\n", ref_avg); // JL
/* perform the regression analysis on 5 hours increment */
for (int pass = 0; pass <= MAX_HOUR - Nhour; pass++) // JL
{
calc_y[0] = ref_avg;
calc_x[0] = pass + 1;
printf("pass %d\ncalc_y[0] = %5.2f, calc_x[0] = %5.2f\n",
pass, calc_y[0], calc_x[0]);
for (int i = 1; i <= Nhour; i++)
{
int n = pass + i - 1;
calc_y[i] = pval[n];
calc_x[i] = pass + i + 1;
printf("calc_y[%d] = %5.2f, calc_x[%d] = %5.2f, n = %2d\n",
i, calc_y[i], i, calc_x[i], n);
}
linear_regression(calc_x, calc_y, Nhour+1, &m, &b);
printf("Slope= %5.2f, intercept = %5.2f\n", m, b);
}
return 0;
}
void linear_regression(const float *x, const float *y, const int n, float *beta1, float *beta0)
{
float sumx1 = 0.0;
float sumy1 = 0.0;
float sumx2 = 0.0;
float sumxy = 0.0;
assert(n > 1);
for (int i = 0; i < n; i++)
{
sumx1 += x[i];
sumy1 += y[i];
sumx2 += (x[i] * x[i]);
sumxy += (x[i] * y[i]);
}
float variance = (sumx2 - ((sumx1 * sumx1) / n));
if (variance != 0.0)
{
*beta1 = (sumxy - ((sumx1 * sumy1) / n)) / variance;
*beta0 = (sumy1 - ((*beta1) * sumx1)) / n;
}
else
{
*beta1 = 0.0;
*beta0 = 0.0;
}
}

Resources