I am very new to C but know my way around [R]. This error could be a very stupid mistake in C.
My C code does kernel smoothing.
*When I comment out the last line of code my function works: results[i] = v; *
This call kills R:
new.y<-zsmooth2( x=c(0:80000), xpts=dat$V2, ypts=dat$V4, h=10000)
* caught segfault *
address 0x1184f8000, cause 'memory not mapped'
Traceback:
1: .C("kernel_smooth", as.double(x), as.double(ypts), as.double(xpts), as.integer(n), as.integer(nxpts), as.double(h), result = double(length(xpts)))
2: zsmooth2(x = c(0:80000), xpts = dat$V2, ypts = dat$V4, h = 10000)
C-code:
#include <R.h>
#include <Rmath.h>
#include <stdio.h>
void kernel_smooth(double *x, double *ypts, double *xpts, int *n, int *nxpts, double *h, double *results){
int i, j;
for(i = 0; i < *n; i++){
double nsum = 0;
double dsum = 0;
double z = x[i] + *h;
double y = x[i] - *h;
for(j = 0; j < *nxpts; j++){
if(xpts[j] < y){
continue;
}
if(xpts[j] > z){
break;
}
double d = (xpts[j] - i) / *h;
double r = dnorm(d, 0, 1, 0);
nsum += r * ypts[j];
dsum += r;
}
Rprintf("test:i %d\n", i);
double v = nsum / dsum;
Rprintf("test:v %f\n", v);
results[i] = v;
}
}
R-code:
dyn.load("~/github/ZevRTricks/smoother1.so")
zsmooth2<-function(x, ypts, xpts, h){
n <- length(x)
nxpts <- length(xpts)
dens <- .C("kernel_smooth", as.double(x), as.double(ypts),
as.double(xpts), as.integer(n), as.integer(nxpts),
as.double(h), result = double(length(xpts)))
dens[["result"]]
}
xpts and ypts are vectors, and in your C code you are trying to access elements 1 to n in each of them. n is the length of x, which is 100 times longer in your second example than in your first example. Compare seq(from = 0, to = 80000 by = 100) to 0:80000, (and while you're at it you can drop the c() from around the 0:80000).
So I guess that xpts and ypts are at least 801 elements long, but less than 80001 elements. You've messed up your indexing somewhere.
Note also that you pass x to your C code, but don't actually use it for anything.
Related
I am using Ruby Fiddle to access a C function to perform some heavy calculations. The C function works perfectly well when called directly, but when used via Fiddle it returns various rows of nans and infs in an unpredictable way. The function operates on matrices that are passed as pointers to arrays.
I have debugged the C code and everything works fine. I have also saved the various parameters passed to the C function to file to be sure that Fiddle was not passing some weird values, but there is no obvious (at least for me) problem.
Additionally it seems that for 'smaller' matrices this does not happen.
Apologies in advance for the code being very long, but this is the only way to exactly reproduce what it is happening. Data for testing is in this file. (gist). You can just copy and paste the Ruby and C test data to the code below.
If it helps, I am working on macos Catalina and Ruby 2.2.4 (requirement).
The C code is the following:
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <math.h>
#include <string.h>
double *mrt(
double *person_total_shortwave,
int rows_pts, int cols_pts,
double *dry_bulb_temperatures,
double *ground_temperatures,
double *atmospheric_longwave,
double *sky_view_factors,
double *shading_view_factors_matrix,
int rows_svf, int cols_svf,
double *shading_temperatures_matrix,
int rows_st, int cols_st,
int size_dbt,
double person_emissivity_shortwave, double person_emissivity_longwave,
double surroundings_emissivity, double ground_emissivity, double ground_person_view_factor);
int save_to_file(char *filename, int m, int n, double *mat)
{
FILE *fp;
int i, j;
if ((fp = freopen(filename, "w", stdout)) == NULL)
{
printf("Cannot open file.\n");
exit(1);
}
for (i = 0; i < m; i++)
for (j = 0; j < n; j++)
if (j == n - 1)
printf("%.17g \n", mat[i * n + j]);
else
printf("%.17g ", mat[i * n + j]);
fclose(fp);
return 0;
}
int main(void)
{
// REPLACE WITH C DATA FROM FILE
double *mrt_result;
mrt_result = mrt(person_total_shortwave[0],
rows_pts, cols_pts,
dry_bulb_temperatures,
ground_temperatures,
atmospheric_longwave,
sky_view_factors,
shading_view_factors_matrix[0],
rows_svf, cols_svf,
shading_temperatures_matrix[0],
rows_st, cols_st,
size_dbt,
person_emissivity_shortwave, person_emissivity_longwave,
surroundings_emissivity, ground_emissivity, ground_person_view_factor);
// save_to_file(rows_pts, cols_pts, mrt_result);
return 0;
}
// https://www.dropbox.com/s/ix06edrrctad421/Calculation%20of%20Mean%20Radiant%20Temperature3.odt?dl=0
double *mrt(
double *person_total_shortwave,
int rows_pts, int cols_pts,
double *dry_bulb_temperatures,
double *ground_temperatures,
double *atmospheric_longwave,
double *sky_view_factors,
double *shading_view_factors_matrix,
int rows_svf, int cols_svf,
double *shading_temperatures_matrix,
int rows_st, int cols_st,
int size_dbt,
double person_emissivity_shortwave, double person_emissivity_longwave,
double surroundings_emissivity, double ground_emissivity, double ground_person_view_factor)
{
save_to_file("PTS.txt", rows_pts, cols_pts, person_total_shortwave);
save_to_file("SVF.txt", 1, cols_svf, sky_view_factors);
save_to_file("SVSM.txt", rows_svf, cols_svf, shading_view_factors_matrix);
save_to_file("STM.txt", rows_st, cols_st, shading_temperatures_matrix);
double *mrt_mat = (double *)calloc(rows_pts * cols_pts, sizeof(double));
save_to_file("MRT_MAT0.txt", rows_pts, cols_pts, mrt_mat);
int t, c, k;
double sigma = 5.67E-8;
double body_area = 1.94;
double tmrt4_shortwave, tmrt4_longwave_ground, tmrt4_atm_longwave, tmrt4_surroundings;
double tmrt4_shading[rows_svf];
memset(tmrt4_shading, 0.0, rows_svf * sizeof(double));
double tmrt4;
double surroundings_view_factor;
// t runs through the timesteps
// c runs through the points in the mesh
for (t = 0; t < rows_pts; t++)
{
for (c = 0; c < cols_pts; c++)
{
tmrt4_shortwave = 1.0 / (sigma * body_area) * (person_emissivity_shortwave / person_emissivity_longwave) * person_total_shortwave[t * cols_pts + c];
// We are assuming that the ground is at ambient temperature
tmrt4_longwave_ground = ground_person_view_factor * ground_emissivity * pow((273.15 + ground_temperatures[t]), 4);
// Here we are using the actual long wave radiation from the sky
tmrt4_atm_longwave = (1.0 - ground_person_view_factor) / sigma * sky_view_factors[c] * atmospheric_longwave[t];
// We need to remove the contribution of all the shading devices
// k runs through the shading devices
surroundings_view_factor = 1.0 - sky_view_factors[c];
for (k = 0; k < rows_svf; k++)
{
surroundings_view_factor -= shading_view_factors_matrix[k * cols_svf + c];
}
tmrt4_surroundings = (1.0 - ground_person_view_factor) * surroundings_view_factor * surroundings_emissivity * pow((273.15 + dry_bulb_temperatures[t] - 0.0), 4);
// We now need to account for all contributions of the shading devices
for (k = 0; k < rows_svf; k++)
{
tmrt4_shading[k] = (1.0 - ground_person_view_factor) * (shading_view_factors_matrix[k * cols_svf + c]) * surroundings_emissivity * pow((273.15 + shading_temperatures_matrix[k * cols_svf + t]), 4);
}
// Finally we add them all (see paper) for the total contribution
tmrt4 = tmrt4_shortwave + tmrt4_longwave_ground + tmrt4_atm_longwave + tmrt4_surroundings;
for (k = 0; k < rows_svf; k++)
{
tmrt4 += tmrt4_shading[k];
}
// Just convert to celsius
mrt_mat[t * cols_pts + c] = pow(tmrt4, 0.25) - 273.15;
}
}
save_to_file("MRT_MAT.txt", rows_pts, cols_pts, mrt_mat);
// double x = 1.5;
// while (1)
// {
// x *= sin(x) / atan(x) * tanh(x) * sqrt(x);
// }
return mrt_mat;
}
and I compile is with clang -g --extra-warnings utils.c -o utils.
The Ruby code is the following
require "fiddle"
require "fiddle/import"
module RG
extend Fiddle::Importer
#handler.handlers.each { |h| h.close unless h.close_enabled? } unless #handler.nil?
GC.start
dlload File.join("utils")
extern "double* mrt(double*, int, int, double*, double*, double*, double*, double*, int, int, double*, int, int, int, double, double, double, double, double)"
def self.mat_to_ptr(matrix)
return Fiddle::Pointer[matrix.flatten.pack("E*")]
end
def self.ptr_to_mat(ptr, rows, cols)
length = rows * cols * Fiddle::SIZEOF_DOUBLE
mat = ptr[0, length]
return mat.unpack("E*").each_slice(cols).to_a
end
def self.mean_radiant_temperature(
person_total_shortwave,
dry_bulb_temperatures,
ground_temperatures,
atmospheric_longwave,
sky_view_factors,
shading_view_factors_matrix,
shading_temperatures_matrix,
person_emissivity_shortwave,
person_emissivity_longwave,
surroundings_emissivity,
ground_emissivity,
ground_person_view_factor
)
rows_pts = person_total_shortwave.size
cols_pts = person_total_shortwave[0].size
person_total_shortwave_pointer = RG.mat_to_ptr(person_total_shortwave)
dry_bulb_temperatures_pointer = RG.mat_to_ptr(dry_bulb_temperatures)
ground_temperatures_pointer = RG.mat_to_ptr(ground_temperatures)
size_dbt = dry_bulb_temperatures.size
atmospheric_longwave_pointer = RG.mat_to_ptr(atmospheric_longwave)
sky_view_factors_pointer = RG.mat_to_ptr(sky_view_factors)
rows_svf = shading_view_factors_matrix.size
if rows_svf > 0
cols_svf = shading_view_factors_matrix[0].size
else
cols_svf = 0
end
shading_view_factors_matrix_pointer = RG.mat_to_ptr(shading_view_factors_matrix)
rows_st = shading_temperatures_matrix.size
if rows_st > 0
cols_st = shading_temperatures_matrix[0].size
else
cols_st = 0
end
shading_temperatures_matrix_pointer = RG.mat_to_ptr(shading_temperatures_matrix)
mrt_pointer = mrt(
person_total_shortwave_pointer,
rows_pts, cols_pts,
dry_bulb_temperatures_pointer,
ground_temperatures_pointer,
atmospheric_longwave_pointer,
sky_view_factors_pointer,
shading_view_factors_matrix_pointer,
rows_svf, cols_svf,
shading_temperatures_matrix_pointer,
rows_st, cols_st,
size_dbt,
person_emissivity_shortwave,
person_emissivity_longwave,
surroundings_emissivity,
ground_emissivity,
ground_person_view_factor
)
return RG.ptr_to_mat(mrt_pointer, rows_pts, cols_pts)
end
end
// REPLACE WITH RUBY DATA FROM FILE
mean_radiant_temperatures = RG.mean_radiant_temperature(
person_total_shortwave,
dry_bulb_temperatures,
ground_temperatures,
atmospheric_longwave,
sky_view_factors,
shading_view_factors_matrix,
shading_temperatures_matrix,
person_emissivity_shortwave,
person_emissivity_longwave,
surroundings_emissivity,
ground_emissivity,
ground_person_view_factor
)
File.open("MRT_MAT_RUBY.txt", "w") do |f|
mean_radiant_temperatures.each do |row|
f.puts row.join(' ')
end
end
If you want to test it, first launch ./utils. It will save a few files on the local folder. Have a look at MRT_MAT.txt.
Now launch the ruby code several times. It will generate the same file, but you will notice that "often" the file will contain random rows with nan and inf. The same data is returned to Ruby and saved in the file MRT_MAT_RUBY.txt in the local directory.
I am quite familiar with Ruby, but C is not really my strength. It would be great being able to debug the C code when called from Ruby, but I don't really know how to do it.
I guess the string created by pack method in mat_to_ptr method is collected by GC.
You should keep the string until pte_to_mat is called.
I am comparing the time it takes Julia to compute the Euclidean distances between two sets of points in 3D space against an equivalent implementation in C. I was very surprised to observe that (for this particular case and my particular implementations) Julia is 22% faster than C. When I also included #fastmath in the Julia version, it would be even 83% faster than C.
This leads to my question: why? Either Julia is more amazing than I originally thought or I am doing something very inefficient in C. I am betting my money on the latter.
Some particulars about the implementation:
In Julia I use 2D arrays of Float64.
In C I use dynamically allocated 1D arrays of double.
In C I use the sqrt function from math.h.
The computations are very fast, therefore I compute them a 1000 times to avoid comparing on the micro/millisecond level.
Some particulars about the compilation:
Compiler: gcc 5.4.0
Optimisation flags: -O3 -ffast-math
Timings:
Julia (without #fastmath): 90 s
Julia (with #fastmath): 20 s
C: 116 s
I use the bash command time for the timings
$ time ./particleDistance.jl (with shebang in file)
$ time ./particleDistance
particleDistance.jl
#!/usr/local/bin/julia
function distance!(x::Array{Float64, 2}, y::Array{Float64, 2}, r::Array{Float64, 2})
nx = size(x, 1)
ny = size(y, 1)
for k = 1:1000
for j = 1:ny
#fastmath for i = 1:nx
#inbounds dx = y[j, 1] - x[i, 1]
#inbounds dy = y[j, 2] - x[i, 2]
#inbounds dz = y[j, 3] - x[i, 3]
rSq = dx*dx + dy*dy + dz*dz
#inbounds r[i, j] = sqrt(rSq)
end
end
end
end
function main()
n = 4096
m = 4096
x = rand(n, 3)
y = rand(m, 3)
r = zeros(n, m)
distance!(x, y, r)
println("r[n, m] = $(r[n, m])")
end
main()
particleDistance.c
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
void distance(int n, int m, double* x, double* y, double* r)
{
int i, j, I, J;
double dx, dy, dz, rSq;
for (int k = 0; k < 1000; k++)
{
for (j = 0; j < m; j++)
{
J = 3*j;
for (i = 0; i < n; i++)
{
I = 3*i;
dx = y[J] - x[I];
dy = y[J+1] - x[I+1];
dz = y[J+2] - x[I+2];
rSq = dx*dx + dy*dy + dz*dz;
r[j*n+i] = sqrt(rSq);
}
}
}
}
int main()
{
int i;
int n = 4096;
int m = 4096;
double *x, *y, *r;
size_t xbytes = 3*n*sizeof(double);
size_t ybytes = 3*m*sizeof(double);
x = (double*) malloc(xbytes);
y = (double*) malloc(ybytes);
r = (double*) malloc(xbytes*ybytes/9);
for (i = 0; i < 3*n; i++)
{
x[i] = (double) rand()/RAND_MAX*2.0-1.0;
}
for (i = 0; i < 3*m; i++)
{
y[i] = (double) rand()/RAND_MAX*2.0-1.0;
}
distance(n, m, x, y, r);
printf("r[n*m-1] = %f\n", r[n*m-1]);
free(x);
free(y);
free(r);
return 0;
}
Makefile
all: particleDistance.c
gcc -o particleDistance particleDistance.c -O3 -ffast-math -lm
Maybe it should be a comment, but the point is that Julia is indeed pretty optimized. In the Julia web page you can see that it can beat C in some cases (mandel).
I see that you are using -ffast-math in your compilation. But, maybe you could do some optimizations in your code (although nowadays compilers are pretty smart and this might not solve the issue).
Instead of using int for your indexes, try to use unsigned int, this allows you to maybe try the following thing;
Instead of multiply by 3, if you use an unsigned you can do a shift and add. This can save some computation time;
In accessing the elements like x[J], maybe try using pointers directly and access the elements in a sequential manner like x+=3 (?);
Instead of int n and int m, try to set them as macros. If they are known in advance, you can take advantage of that.
Does the malloc make difference in this case? If n and m are known, fixed size arrays would reduce the time spent for the OS allocate memory.
There might be a few other things, but Julia is pretty optimized with real time compilation, so everything that is constant and is known in advance is used in favor of it. I have tried Julia with no regrets.
Your index calculation in C is rather slow
Try something like the following (I did not compiled it, it may have still errors, just too visualize the idea):
void distance(int n, int m, double* x, double* y, double* r)
{
int i, j;
double dx, dy, dz, rSq;
double* X, *Y, *R;
for (int k = 0; k < 1000; k++)
{
R = r;
Y = y;
for (j = 0; j < m; j++)
{
X = x;
for (i = 0; i < n; i++)
{
dx = Y[0] - *X++;
dy = Y[1] - *X++;
dz = Y[2] - *X++;
rSq = dx*dx + dy*dy + dz*dz;
*R++ = sqrt(rSq);
}
Y += 3;
}
}
}
Alternatively you could try, it might be a little bit faster (one increment instead of 3)
dx = Y[0] - X[0];
dy = Y[1] - X[1];
dz = Y[2] - X[2];
X+=3;
Y[x] is the same as *(Y+x).
Good luck
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.
I am constantly facing a fatal error when calling a C function in R and I suspect it may be because of the way I have used "realloc" routine for variable n_k in the gCRSF_gibbs function. Can somebody tell me if the reallocation of memory to n_k is correct or not?
void gCRSF_gibbs(double *z, double **n_k, double *SampleDex,
double *r, double *a, double *p,
int *Ksize, int *WordNum) {
int i, j, k;
double mass;
double *prob_cumsum;
double cum_sum, probrnd;
prob_cumsum = (double *) calloc(Ksize[0],sizeof(double));
mass = r[0]*pow(p[0],-a[0]);
for (i=0;i<WordNum[0];i++){
j = (int) SampleDex[i] -1;
k = (int) z[j] -1;
if(z[j]>0){
(*n_k)[k]--;
}
for (cum_sum=0, k=0; k<Ksize[0]; k++) {
cum_sum += (*n_k)[k]-a[0];
prob_cumsum[k] = cum_sum;
}
if ( ((double) rand() / RAND_MAX * (cum_sum + mass) < cum_sum)){
probrnd = (double)rand()/(double)RAND_MAX*cum_sum;
k = BinarySearch(probrnd, prob_cumsum, Ksize[0]);
}
else{
for (k=0; k<Ksize[0]; k++){
if ((int) (*n_k)[k]==0){
break;
}
}
if (k==Ksize[0]){
Ksize[0]++;
realloc(*n_k,sizeof(**n_k)*Ksize[0]);
(*n_k)[Ksize[0]-1]=0;
prob_cumsum = realloc(prob_cumsum,sizeof(*prob_cumsum)*Ksize[0]);
}
}
z[j] = k+1;
(*n_k)[k]++;
}
free(prob_cumsum);}
And this is how it is called in R:
gCRSF_gibbs <- function(z, n_k, sampleDex, r, a, p){
out <- .C("gCRSF_gibbs", z=as.double(z), n_k=as.double(n_k),
SampleDex=as.double(sampleDex), r=as.double(r), a=as.double(a),
p=as.double(p), Ksize=as.integer(length(n_k)),
WordNum=as.integer(length(sampleDex)))
out}
You're using realloc wrong. It should be:
*n_k = realloc(*n_k,sizeof(**n_k)*Ksize[0]);
You always want to use realloc like p = realloc(p, size). Otherwise, if the buffer gets moved by realloc, *n_k will be pointing to a freed pointer.
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;
}
}