(Disclaimer: I am terrible with math and am coming from JavaScript, so I apologize for any inaccuracies and will do my best to correct them.)
The example on Rosetta Code shows how to calculate coefficients using gsl. Here is the code:
polifitgsl.h:
#ifndef _POLIFITGSL_H
#define _POLIFITGSL_H
#include <gsl/gsl_multifit.h>
#include <stdbool.h>
#include <math.h>
bool polynomialfit(int obs, int degree,
double *dx, double *dy, double *store); /* n, p */
#endif
polifitgsl.cpp:
#include "polifitgsl.h"
bool polynomialfit(int obs, int degree,
double *dx, double *dy, double *store) /* n, p */
{
gsl_multifit_linear_workspace *ws;
gsl_matrix *cov, *X;
gsl_vector *y, *c;
double chisq;
int i, j;
X = gsl_matrix_alloc(obs, degree);
y = gsl_vector_alloc(obs);
c = gsl_vector_alloc(degree);
cov = gsl_matrix_alloc(degree, degree);
for(i=0; i < obs; i++) {
for(j=0; j < degree; j++) {
gsl_matrix_set(X, i, j, pow(dx[i], j));
}
gsl_vector_set(y, i, dy[i]);
}
ws = gsl_multifit_linear_alloc(obs, degree);
gsl_multifit_linear(X, y, c, cov, &chisq, ws);
/* store result ... */
for(i=0; i < degree; i++)
{
store[i] = gsl_vector_get(c, i);
}
gsl_multifit_linear_free(ws);
gsl_matrix_free(X);
gsl_matrix_free(cov);
gsl_vector_free(y);
gsl_vector_free(c);
return true; /* we do not "analyse" the result (cov matrix mainly)
to know if the fit is "good" */
}
main.cpp (note I've replaced the sample numbers for x any y with my own):
#include <stdio.h>
#include "polifitgsl.h"
#define NP 11
double x[] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
double y[] = {98.02, 98.01, 98.01, 98.02, 97.98, 97.97, 97.96, 97.94, 97.96, 97.96, 97.97, 97.97, 97.94, 97.94, 97.94, 97.92, 97.96, 97.9, 97.85, 97.9};
#define DEGREE 3
double coeff[DEGREE];
int main()
{
int i;
polynomialfit(NP, DEGREE, x, y, coeff);
for(i=0; i < DEGREE; i++) {
printf("%lf\n", coeff[i]);
}
return 0;
}
And here is the output:
98.030909
-0.016182
0.000909
So that gives me the coefficients. But what I really want is the actual fitted points. In JavaScript, I've used the regression package to calculate the points:
var regression = require('regression');
var calculateRegression = function(values, degree) {
var data = [];
var regressionOutput;
var valuesCount = values.length;
var i = 0;
// Format the data in a way the regression library expects.
for (i = 0; i < valuesCount; i++) {
data[i] = [i, values[i]];
}
// Use the library to calculate the regression.
regressionOutput = regression('polynomial', data, degree);
return regressionOutput;
};
var y = [98.02, 98.01, 98.01, 98.02, 97.98, 97.97, 97.96, 97.94, 97.96, 97.96, 97.97, 97.97, 97.94, 97.94, 97.94, 97.92, 97.96, 97.9, 97.85, 97.9];
console.log(calculateRegression(y, 3));
Which produces:
{ equation:
[ 98.02987916431594,
-0.017378390369880512,
0.0015748071645344357,
-0.00005721503635571101 ],
points:
[ [ 0, 98.02987916431594 ],
[ 1, 98.01401836607424 ],
[ 2, 98.00096389194348 ],
[ 3, 97.9903724517055 ],
[ 4, 97.98190075514219 ],
[ 5, 97.97520551203543 ],
[ 6, 97.96994343216707 ],
[ 7, 97.96577122531896 ],
[ 8, 97.96234560127297 ],
[ 9, 97.959323269811 ],
[ 10, 97.95636094071487 ],
[ 11, 97.95311532376647 ],
[ 12, 97.94924312874768 ],
[ 13, 97.94440106544033 ],
[ 14, 97.93824584362629 ],
[ 15, 97.93043417308745 ],
[ 16, 97.92062276360569 ],
[ 17, 97.90846832496283 ],
[ 18, 97.89362756694074 ],
[ 19, 97.87575719932133 ] ],
string: 'y = 0x^3 + 0x^2 + -0.02x + 98.03' }
(Note there are floating point issues in JavaScript, so the numbers aren't perfectly exact.)
points here is what I'm wanting to generate using gsl. Is there a way I can do this?
Chad, if I understand what you are needing, you simply need to compute the values based on the polynomial equation using the coefficients you found with your polynomialfit function. After you compute the coefficients, you can find the value y for any x (for DEGREE = 3) with the equation:
y = x^2*(coeff2) + x*(coeff1) + coeff0
or in C-syntax
y = x*x*coeff[2] + x*coeff[1] + coeff[0];
You can modify your main.cpp as follows (you should rename both main.cpp to main.c and polyfitgsl.cpp to polyfitgsl.c -- as they are both C-source files, not C++)
#include <stdio.h>
#include "polifitgsl.h"
#define NP 20
double x[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
double y[] = { 98.02, 98.01, 98.01, 98.02, 97.98,
97.97, 97.96, 97.94, 97.96, 97.96,
97.97, 97.97, 97.94, 97.94, 97.94,
97.92, 97.96, 97.9, 97.85, 97.9 };
#define DEGREE 3
double coeff[DEGREE];
int main (void)
{
int i;
polynomialfit (NP, DEGREE, x, y, coeff);
printf ("\n polynomial coefficients:\n\n");
for (i = 0; i < DEGREE; i++) {
printf (" coeff[%d] : %11.7lf\n", i, coeff[i]);
}
putchar ('\n');
printf (" computed values:\n\n x y\n");
for (i = 0; i < (int)(sizeof x/sizeof *x); i++)
printf (" %2d, %11.7lf\n", i,
i*i*coeff[2] + i*coeff[1] + coeff[0]);
putchar ('\n');
return 0;
}
Which provides the following output:
Example Use/Output
$ ./bin/main
polynomial coefficients:
coeff[0] : 98.0132468
coeff[1] : -0.0053003
coeff[2] : -0.0000558
computed values:
x y
0, 98.0132468
1, 98.0078906
2, 98.0024229
3, 97.9968435
4, 97.9911524
5, 97.9853497
6, 97.9794354
7, 97.9734094
8, 97.9672718
9, 97.9610226
10, 97.9546617
11, 97.9481891
12, 97.9416049
13, 97.9349091
14, 97.9281016
15, 97.9211825
16, 97.9141517
17, 97.9070093
18, 97.8997553
19, 97.8923896
That seems like what you are asking for. Look it over, compare your values and let me know if you need additional help.
Cleaning Up A Bit Further
Just to clean the code up a bit further, since there is no need for global declaration of x, y, or coeff, and using an enum to define the constants DEGREE and NP, a tidier version would be:
#include <stdio.h>
#include "polifitgsl.h"
enum { DEGREE = 3, NP = 20 };
int main (void)
{
int i;
double x[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
double y[] = { 98.02, 98.01, 98.01, 98.02, 97.98,
97.97, 97.96, 97.94, 97.96, 97.96,
97.97, 97.97, 97.94, 97.94, 97.94,
97.92, 97.96, 97.9, 97.85, 97.9 };
double coeff[DEGREE] = {0};
polynomialfit (NP, DEGREE, x, y, coeff);
printf ("\n polynomial coefficients:\n\n");
for (i = 0; i < DEGREE; i++)
printf (" coeff[%d] : %11.7lf\n", i, coeff[i]);
putchar ('\n');
printf (" computed values:\n\n x y\n");
for (i = 0; i < (int)(sizeof x/sizeof *x); i++)
printf (" %2d, %11.7lf\n", i,
i*i*coeff[2] + i*coeff[1] + coeff[0]);
putchar ('\n');
return 0;
}
I had the same problem and have taken the answers above and added a solution for direct calculation (without gsl) taken from http://www.cplusplus.com/forum/general/181580/
Below, you find a standalone test program with a gsl-based and a direct calculation solution.
I have done some profiling runs and the performance of direct calculation is an impressive 65 times higher on my system, 5.22s vs. 0.08s for 1000 calls to the respective functions.
As a side note, the direct calculation uses Cramer's rule, so you should be careful with ill conditioned data. Normally I would avoid Cramer's but using a full linear system solver for a 3x3 system seems overkill to me.
/*
* =====================================================================================
*
* Filename: polyfit.cpp
*
* Description: Least squares fit of second order polynomials
* Test program using gsl and direct calculation
* Version: 1.0
* Created: 2017-07-17 09:32:55
* Compiler: gcc
*
* Author: Bernhard Brunner, brb_blog#epr.ch
* References: This code was merged, adapted and optimized from these two sources:
* http://www.cplusplus.com/forum/general/181580/
* https://stackoverflow.com/questions/36522882/how-can-i-use-gsl-to-calculate-polynomial-regression-data-points
* http://brb.epr.ch/blog/blog:least_squares_regression_of_parabola
* Build: compile and link using
* g++ -c -o polifitgsl.o polifitgsl.cpp
* gcc polifitgsl.o -lgsl -lm -lblas -o polifitgsl
*
* Profiling:
* valgrind --tool=callgrind ./polifitgsl
* kcachegrind
*
* polynomialfit takes 5.22s for 1000 calls
* findQuadCoefficients takes 0.08s for 1000 calls
* 65x faster
* =====================================================================================
*/
#include <stdio.h>
#include <gsl/gsl_multifit.h>
#include <stdbool.h>
#include <math.h>
bool polynomialfit(int obs, int degree,
double *dx, double *dy, double *store); /* n, p */
double x[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18, 19};
double y[] = { 98.02, 98.01, 98.01, 98.02, 97.98,
97.97, 97.96, 97.94, 97.96, 97.96,
97.97, 97.97, 97.94, 97.94, 97.94,
97.92, 97.96, 97.9, 97.85, 97.9 };
#define NP (sizeof(x)/sizeof(double)) // 20
#define DEGREE 3
double coeff[DEGREE];
bool findQuadCoefficients(double timeArray[], double valueArray[], double *coef, double &critPoint, int PointsNum){
const double S00=PointsNum;//points number
double S40=0, S10=0, S20=0, S30=0, S01=0, S11=0, S21 = 0;
// const double MINvalue = valueArray[0];
// const double MINtime = timeArray[0];
for (int i=0; i<PointsNum; i++ ){
double value = valueArray[i]; // - MINvalue); //normalizing
// cout << "i=" << i << " index=" << index << " value=" << value << endl;
int index = timeArray[i]; // - MINtime;
int index2 = index * index;
int index3 = index2 * index;
int index4 = index3 * index;
S40+= index4;
S30+= index3;
S20+= index2;
S10+= index;
S01 += value;
S11 += value*index;
S21 += value*index2;
}
double S20squared = S20*S20;
//minors M_ij=M_ji
double M11 = S20*S00 - S10*S10;
double M21 = S30*S00 - S20*S10;
double M22 = S40*S00 - S20squared;
double M31 = S30*S10 - S20squared;
double M32 = S40*S10 - S20*S30;
// double M33 = S40*S20 - pow(S30,2);
double discriminant = S40*M11 - S30*M21 + S20*M31;
// printf("discriminant :%lf\n", discriminant);
if (abs(discriminant) < .00000000001) return false;
double Da = S21*M11
-S11*M21
+S01*M31;
coef[2] = Da/discriminant;
// cout << "discriminant=" << discriminant;
// cout << " Da=" << Da;
double Db = -S21*M21
+S11*M22
-S01*M32;
coef[1] = Db/discriminant;
// cout << " Db=" << Db << endl;
double Dc = S40*(S20*S01 - S10*S11)
- S30*(S30*S01 - S10*S21)
+ S20*(S30*S11 - S20*S21);
coef[0] = Dc/discriminant;
// printf("c=%lf\n", c);
critPoint = -Db/(2*Da); // + MINtime; //-b/(2*a)= -Db/discriminant / (2*(Da/discriminant)) = -Db/(2*Da);
return true;
}
bool polynomialfit(int obs, int degree,
double *dx, double *dy, double *store) /* n, p */
{
gsl_multifit_linear_workspace *ws;
gsl_matrix *cov, *X;
gsl_vector *y, *c;
double chisq;
int i, j;
X = gsl_matrix_alloc(obs, degree);
y = gsl_vector_alloc(obs);
c = gsl_vector_alloc(degree);
cov = gsl_matrix_alloc(degree, degree);
for(i=0; i < obs; i++) {
for(j=0; j < degree; j++) {
gsl_matrix_set(X, i, j, pow(dx[i], j));
}
gsl_vector_set(y, i, dy[i]);
}
ws = gsl_multifit_linear_alloc(obs, degree);
gsl_multifit_linear(X, y, c, cov, &chisq, ws);
/* store result ... */
for(i=0; i < degree; i++) {
store[i] = gsl_vector_get(c, i);
}
gsl_multifit_linear_free(ws);
gsl_matrix_free(X);
gsl_matrix_free(cov);
gsl_vector_free(y);
gsl_vector_free(c);
return true; /* we do not "analyse" the result (cov matrix mainly)
to know if the fit is "good" */
}
void testcoeff(double *coeff)
{
printf ("\n polynomial coefficients\n");
for (int i = 0; i < DEGREE; i++) {
printf (" coeff[%d] : %11.7lf\n", i, coeff[i]);
}
putchar ('\n');
printf (" computed values:\n\n x, yi, yip\n");
for (unsigned i = 0; i < NP; i++) {
printf ("%2u,%.7lf,%.7lf\n", i,
y[i],
i*i*coeff[2] + i*coeff[1] + coeff[0]);
}
putchar ('\n');
}
int main (void)
{
#define ITER 1000
for (int i=0; i< ITER; i++) {
polynomialfit (NP, DEGREE, x, y, coeff);
}
testcoeff(coeff);
double sx;
for (int i=0; i< ITER; i++) {
findQuadCoefficients(x, y, coeff, sx, NP);
}
printf("critical point %lf\n", sx);
testcoeff(coeff);
return 0;
}
References:
http://www.cplusplus.com/forum/general/181580/
http://mathworld.wolfram.com/LeastSquaresFittingPolynomial.html
Related
I am creating digital clock with an output using ascii and I made a large number consisting of five lines. I want to move the number using gotoxy but only the first line moves and the rest line is ignoring the y coordinates.
How can I move my entire number using gotoxy while my printf has newlines?
#include <stdio.h>
#include <time.h>
#include <windows.h>
#include<conio.h>
void gotoxy(int col, int row);
void disp0();
int count=219;
int main()
{
gotoxy(10,10);disp0();
}
void gotoxy(int col, int row)
{
COORD coord;
coord.X = col; coord.Y = row;
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), coord);
}
void disp0(){
printf("%c%c%c\n%c %c\n%c %c\n%c %c\n%c%c%c",count,count,count,count,count,count,count,count,count,count,count,count);//0
}
This is the output I get:
You need to do a gotoxy and a printf for every individual digit. No \n should be used. If you want to be fancy you can use trigonometry, like in this very sloppy example:
#include <stdio.h>
#include <windows.h>
#include <math.h>
void gotoxy(int x, int y)
{
SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE),
(COORD){ .X=x, .Y=y });
}
int main()
{
const int center_x = 12;
const int center_y = 12;
const int radius = 6;
double angle = 0;
int clock [12] = {3, 2, 1, 12, 11, 10, 9, 8, 7, 6, 5, 4};
for(int i=0; i<12; i++)
{
int x = round(radius * cos(angle));
int y = round(radius * -sin(angle)); // - to shift y axis on console coord system
angle += (2.0 * 3.1415) / 12.0;
// 2*x rough estimate to compensate for font height vs width:
gotoxy(center_x + 2*x, center_y + y);
printf("%d", clock[i]);
}
gotoxy(1,center_y*2);
}
Ugly output:
12
11 1
10 2
9 3
8 4
7 5
6
I am trying to use the built-in RK2imp method for solving a slightly modified version of the van der pol problem given in the GSL sample examples for using adaptive solvers for integration. However, I keep getting this "error: invalid pointer".
I am attaching my code here
#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
#define ABTOL 1e-18
#define A 2.00861986087484313650940188
#define mu 1.0
#define TEND 6.6632868593231301896996820305
double eps_abs=ABTOL, eps_rel=0.0, tend=TEND;
int func (double t, const double y[], double f[], void *params)
{
(void)(t); /* avoid unused parameter warning */
f[0] = y[1];
f[1] = -y[0] - mu*y[1]*(y[0]*y[0] - 1);
return GSL_SUCCESS;
}
int jac (double t, const double y[], double *dfdy, double dfdt[], void *params)
{
(void)(t); /* avoid unused parameter warning */
gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);
gsl_matrix * m = &dfdy_mat.matrix;
gsl_matrix_set (m, 0, 0, 0.0);
gsl_matrix_set (m, 0, 1, 1.0);
gsl_matrix_set (m, 1, 0, -2.0*mu*y[0]*y[1] - 1.0);
gsl_matrix_set (m, 1, 1, -mu*(y[0]*y[0] - 1.0));
dfdt[0] = 0.0;
dfdt[1] = 0.0;
return GSL_SUCCESS;
}
int main (void)
{
const gsl_odeiv2_step_type * T = gsl_odeiv2_step_rk2imp;
gsl_odeiv2_step * s = gsl_odeiv2_step_alloc (T, 2);
gsl_odeiv2_control * c = gsl_odeiv2_control_y_new (eps_abs, eps_rel);
gsl_odeiv2_evolve * e = gsl_odeiv2_evolve_alloc (2);
gsl_odeiv2_system sys = {func, jac, 2, NULL};
double t = 0.0, t1 = TEND;
double h = 1e-6;
double y[2] = { A, 0.0 };
while (t < t1)
{
int status = gsl_odeiv2_evolve_apply (e, c, s, &sys, &t, t1, &h, y);
if (status != GSL_SUCCESS)
{
printf ("error: %s\n", gsl_strerror (status));
break;
}
printf ("%.5e %.5e %.5e\n", t, y[0], y[1]);
}
gsl_odeiv2_evolve_free (e);
gsl_odeiv2_control_free (c);
gsl_odeiv2_step_free (s);
return 0;
}
This is the output I get:
error: invalid pointer
I am aware that I could be making a very simple (and silly) mistake but for some reason I am not able to see it. I would really appreciate any help! Thank you.
As I understand it, the inappropriate
stepping function
for the numerical integration method (Runge-Kutta). It’s better to use explicit methods here, you can even use gsl_odeiv2_step_rk2 stepping function, but the solution will converge for a very long time.
OR you can use implicit integration methods, but you need to use step driver:
#include <stdio.h>
#include <gsl/gsl_errno.h>
#include <gsl/gsl_matrix.h>
#include <gsl/gsl_odeiv2.h>
#define ABTOL 1e-18
#define A 2.00861986087484313650940188
#define mu 1.0
#define TEND 6.6632868593231301896996820305
double eps_abs=ABTOL, eps_rel=0.0, tend=TEND;
int func (double t, const double y[], double f[], void *params)
{
(void)(t); /* avoid unused parameter warning */
f[0] = y[1];
f[1] = -y[0] - mu*y[1]*(y[0]*y[0] - 1);
return GSL_SUCCESS;
}
int jac (double t, const double y[], double *dfdy, double dfdt[], void *params)
{
(void)(t); /* avoid unused parameter warning */
gsl_matrix_view dfdy_mat = gsl_matrix_view_array (dfdy, 2, 2);
gsl_matrix * m = &dfdy_mat.matrix;
gsl_matrix_set (m, 0, 0, 0.0);
gsl_matrix_set (m, 0, 1, 1.0);
gsl_matrix_set (m, 1, 0, -2.0*mu*y[0]*y[1] - 1.0);
gsl_matrix_set (m, 1, 1, -mu*(y[0]*y[0] - 1.0));
dfdt[0] = 0.0;
dfdt[1] = 0.0;
return GSL_SUCCESS;
}
int main (void)
{
const gsl_odeiv2_step_type * T = gsl_odeiv2_step_msadams;
// with "gsl_odeiv2_step_rk2imp" stepping function the solution
// converges VERY SLOWLY and may be "failure" error at the end
gsl_odeiv2_step * s = gsl_odeiv2_step_alloc (T, 2);
gsl_odeiv2_control * c = gsl_odeiv2_control_y_new (eps_abs, eps_rel);
gsl_odeiv2_evolve * e = gsl_odeiv2_evolve_alloc (2);
gsl_odeiv2_system sys = {func, jac, 2, NULL};
gsl_odeiv2_driver * d = gsl_odeiv2_driver_alloc_y_new(&sys, T, 1e-6, 1e-6, 1e-6 );
gsl_odeiv2_step_set_driver(s, d);
double t = 0.0, t1 = TEND;
double h = 1e-6;
double y[2] = { A, 0.0 };
while (t < t1)
{
int status = gsl_odeiv2_evolve_apply (e, c, s, &sys, &t, t1, &h, y);
if (status != GSL_SUCCESS)
{
printf ("error: %s\n", gsl_strerror (status));
break;
}
printf ("%.5e %.5e %.5e\n", t, y[0], y[1]);
}
gsl_odeiv2_evolve_free (e);
gsl_odeiv2_control_free (c);
gsl_odeiv2_step_free (s);
return 0;
}
I have already posted a similar code, but now it produces nan=( May be I declare angles in wrong way. This is an integrator:
#include<math.h>
#include<stdio.h>
#include<stdlib.h>
#include "rk4.h"
#define M_PI 3.141592653589793
void integrator(vector_function f, int n, double* y,
double t, double dt, double* yn)
{
double k1[n],k2[n],k3[n],k4[n],ytmp[n];
double deriv[n]; // note that dynamic arrays are
// a C99 feature -- check your compiler flags
f(y,t,deriv);
for(int i=0;i<n;++i)
{
k1[i]=deriv[i]*dt;
ytmp[i]=y[i]+0.5*dt*deriv[i];
}
f(ytmp,t+0.5*dt,deriv);
for(int i=0;i<n;++i)
{
k2[i]=dt*deriv[i];
ytmp[i]=y[i]+0.5*dt*deriv[i];
}
f(ytmp,t+0.5*dt,deriv);
for(int i=0;i<n;++i)
{
k3[i]=dt*deriv[i];
ytmp[i]=y[i]+dt*deriv[i];
}
f(ytmp,t+dt,deriv);
for(int i=0;i<n;++i) k4[i]=dt*deriv[i];
for(int i=0;i<n;++i)
{
yn[i]=y[i]+(k1[i]+2*k2[i]+2*k3[i]+k4[i])/6;
}
}
This is a function:
#include<stdio.h>
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include "rk4.h"
//initial conditions
#define M_PI 3.141592653589793
#define ms 1.9891e30
#define me 5.9736e24
#define a 149598261e3
#define e 0.0167112303531389
#define G 6.67428e-11
#define Tday 86164.1
#define Tyear 31552844.28
#define I1 8.008e37
#define I3 8.034e37
#define Theta0 24.45*2*M_PI/360.0
void F(double* y, double t, double* f);
int main(int argc, char ** argv)
{
double tf;
int m;
printf("Please input the number of years\n");
scanf("%lf",&tf);
tf = tf*Tyear;
printf("please input the number of steps \n");
scanf("%d",&m);
double yn[18];
double t=0;
double dt=(tf-t) / m;
double re0 = a*(1+e)*ms/(me+ms);
double KE = G*ms*me*(1.0/(1+e)-0.5)/a;
double ve0 = sqrt(2*KE/(me*(1+me/ms)));
double rs0 = -me*re0/ms;
double vs0 = -me*ve0/ms;
//angles
double vpsy0 = (2.0*M_PI)/Tday;
double y[18]= {re0, 0, 0, 0, ve0, 0, rs0, 0, 0, 0, vs0, 0, 0, Theta0, 0, 0, 0, vpsy0};
//integrator
for (int k=0; k<m;k++)
{
integrator(F, 18, y, t, dt, yn);
t=t+dt;
for(int i=0; i<18; ++i) y[i] = yn[i];
printf("%e ", t); for(int i=0; i<18; ++i) printf("%e ", y[i]);
printf("\n");
}
// printf("the integrated components re are %e %e %e\n",yn[0], yn[1], yn[2]);
// printf("the integrated components ve are %e %e %e\n",yn[3], yn[4], yn[5]);
// printf("the integrated components rs are %e %e %e\n",yn[6], yn[7], yn[8]);
// printf("the integrated components vs are %e %e %e\n",yn[9], yn[10], yn[11]);
// printf("the intigrated theta is %lf\n",yn[2]);
//printf("%lf\n",dcube);
//fprintf(f,"%lf/t%lf/n",y[0],y[2]);
//fclose(f);
return 0;
}
void F(double* y, double t, double* f)
{
double d[3] = {y[0]-y[6], y[1]-y[7], y[5]-y[8]};
double dcube;
double dsqrt;
double d5;
double d3 = d[0]*sin(y[13])*sin(y[14])-d[1]*cos(y[13])*sin(y[14])+d[2]*cos(y[14]);
double c0;
dsqrt = d[0]*d[0] + d[1]*d[1] + d[2]*d[2];
dcube = pow(dsqrt, 1.5);
d5 = pow(dsqrt, 2.5);
c0 = 2.0*M_PI/Tday;
//the term angular[] (different for every component)
double a1 = sin(y[12])*sin(y[13]);
double a2 = -cos(y[12])*sin(y[13]);
double a3 = cos(y[13]);
double angular[3]={a1, a2, a3};
for (int i = 0; i<3; ++i)
{
//velocity Earth
f[i] = y[3+i];
//acceleration Earth
f[3+i] = -(G*ms*d[i]/dcube) + (3.0*G*ms*(I1-I3)*((d[i]/2.0) - (5.0*pow(d3, 2)*d[i]/2.0*dsqrt) + (d3*angular[i]/2.0)))/d5*me;
//Velocity Sun
f[6+i] = y[9+i];
//acceleration Sun
f[9+i] = (G*me*d[i]/dcube) - (3.0*G*(I1-I3)*((d[i]/2.0) - (5.0*pow(d3, 2)*d[i]/2.0*dsqrt) + (d3*angular[i]/2.0)))/d5;
}
//angles
f[12] = y[15];
f[13] = y[16];
f[14] = y[17];
f[15] = (2.0*y[15]*y[16]*cos(y[13]) + I3*c0*y[16]/I1 + 3.0*G*ms*(I1-I3)*d3*(y[0]*cos(y[12])+y[1]*sin(y[12])))/sin(y[13]);
f[16] = pow(y[15], 2)*sin(y[13])*cos(y[13]) - (I3*c0*y[15]*sin(y[13])/I1) + 3.0*G*ms*(I1-I3)*d3*((d[0]*sin(y[12])-d[1]*cos(y[12]))*cos(y[13])-d[2]*sin(y[13]))/(d5*I1);
f[17] = y[15]*y[16]*sin(y[13]) - f[16]*cos(y[13]);
}
and this is a Makefile:
integrator: integrator.o rk4.o
gcc -o $# $^ -lm
integrator.o: integrator.c
gcc -g -c integrator.c -std=c99 -lm
rk4.o: rk4.c
gcc -g -c rk4.c -std=c99 -lm
clean:
rm -rf *.o integrator
Help, please! There are still a probability that I have messed up formulas, but I assume that there also wrong declaration of something or some overflow...
Thank you all in advance!
Given your math, this is probably how you end up with NaN.
Step 1: something / 0 -> INF (or -INF)
Step 2: something * INF -> NaN
So put tests in your code for every divisor to see if it is or close to zero: I usually test that the value is (-1e-20 < x ) && ( x < 1e-20 )
You can also use the tests in <math.h> isinf() and isnan() to test as you go.
Assuming that these functions are already given:
include <stdio.h> /* printf */
include "fractions.h" /* struct FRACTION, add_fractions */
struct FRACTION make_fraction(int numerator, int denominator)
{
struct FRACTION f;
f.numerator = numerator;
f.denominator = denominator;
return f;
}
void test_fraction(int numerator1, int denominator1,
int numerator2, int denominator2)
{
struct FRACTION a = make_fraction(numerator1, denominator1);
struct FRACTION b = make_fraction(numerator2, denominator2);
struct FRACTION c = add_fractions(&a, &b);
printf("%i/%i + %i/%i = %i/%i\n", a.numerator, a.denominator,
b.numerator, b.denominator,
c.numerator, c.denominator);
}
void testGCD(void)
{
int m, n;
m = 15; n = 18; /* GCD is 3 */
printf("GCD of %i and %i is %i\n", m, n, GCD(m, n));
printf("GCD of %i and %i is %i\n", n, m, GCD(n, m));
m = 80; n = 20; /* GCD is 20 */
printf("GCD of %i and %i is %i\n", m, n, GCD(m, n));
printf("GCD of %i and %i is %i\n", n, m, GCD(n, m));
m = 21; n = 47; /* GCD is 1 */
printf("GCD of %i and %i is %i\n", m, n, GCD(m, n));
printf("GCD of %i and %i is %i\n", n, m, GCD(n, m));
m = 68; n = 153; /* GCD is 17 */
printf("GCD of %i and %i is %i\n", m, n, GCD(m, n));
printf("GCD of %i and %i is %i\n", n, m, GCD(n, m));
}
int main(void)
{
testGCD();
test_fraction(2, 3, 1, 6);
test_fraction(1, 5, 4, 9);
test_fraction(3, 7, 12, 21);
test_fraction(5, 8, 3, 16);
test_fraction(7, 8, 3, 12);
test_fraction(0, 8, 3, 16);
test_fraction(1, 1, 3, 16);
test_fraction(5, 8, -3, 16);
test_fraction(1, 5, -4, 9);
test_fraction(-1, 5, -4, 9);
return 0;
}
My task is to write GCD() and add_fractions(), and this is what I have written:
include "fractions.h"
struct FRACTION add_fractions(const struct FRACTION *a, const struct FRACTION *b)
{
struct FRACTION c ; /*result struct*/
/* int GCD_a = GCD(a.numerator, a.denominator); GCD of the fraction a*/
/*int GCD_b = GCD(b.numerator, b.denominator); GCD of the fraction b*/
c.numerator = (a.numerator) + (b.numerator);
c.denominator = a.denominator ;
return c;
/* struct FRACTION empty;*/
/*return empty;*/
}
int GCD(int a, int b)
{
/*Variables*/
int remainder = 0; /*remainder*/
int larger = a;
int smaller = b;
remainder = larger % smaller;
while (remainder != 0)
{
larger = smaller;
smaller = remainder;
remainder = larger % smaller;
}
return smaller;
}
Assuming that for the moment both denominators are equals, why I can't run this with Cygwin? I use this command to compile
gcc -Wall -Wextra -ansi -pedantic -Wno-unused-parameters main.c fractions.c -o fractions.exe
and I have two errors: (Cygwin is in Spanish on my computer so I am not sure that what I am going to write is the exact translation):
error: trying to put "numerator" in something which is not a struct
(and the same for denominator)
What is the problem?
const struct FRACTION *a, const struct FRACTION *b
So a and b are pointers to a constant struct FRACTION. Then later you write:
c.numerator = (a.numerator) + (b.numerator);
you don't access members of struct pointers using ., but using ->, this should be
c.numerator = a->numerator + b->numerator;
P. s. 1: the parentheses are not needed, don't put them in superfluously, they decrease readability.
P. s. 2: your addition formula is broken, use
c.numerator = a->numerator * b->denominator + b->numerator * a->denominator;
c.denominator = a->denominator * b->denominator;
instead.
In your add_fractions function, you've declared a and b as pointers to struct FRACTION:
struct FRACTION add_fractions(const struct FRACTION *a, const struct FRACTION *b)
Since a and b are pointers, not structs, you can't write things like a.numerator.
You either need to dereference a and b before using the . operator:
c.numerator = ((*a).numerator) + ((*b).numerator);
c.denominator = (*a).denominator ;
or use the -> component selection operator, which is a shorthand way of doing the same thing:
c.numerator = (a->numerator) + (b->numerator);
c.denominator = a->denominator ;
In addition to user529758's point that your addition algorithm should be
n1 * d2 + n2 * d1
= ------------------
d1 * d2
I believe Jonathan's point needs to be emphasized that you will then need to divide the numerator and denominator of the result through by the GCD to reduce the resulting fraction to its lowest form.
For example, you can implement a new function to do the reduction:
struct FRACTION reduce_fraction(const struct FRACTION *frac)
{
struct FRACTION reduced;
int gcd = GCD(frac->numerator, frac->denominator);
reduced.numerator = frac->numerator / gcd;
reduced.denominator = frac->denominator / gcd;
return reduced;
}
Your add_fraction function will now look like this:
struct FRACTION add_fractions(const struct FRACTION *a, const struct FRACTION *b)
{
struct FRACTION c;
c.numerator = (a->numerator * b->denominator) + (b->numerator * a->denominator);
c.denominator = a->denominator * b->denominator;
return reduce_fraction(&c);
}
Also, given that you've done the hard work in determining what the result should be in the comments, instead of printfing to stdout, why not assert these - this provides the basis for automated unit tests:
#include <assert.h>
...
m = 15; n = 18;
assert(GCD(m, n) == 3);
assert(GCD(m, n) == GCD(n,m));
m = 80; n = 20;
assert(GCD(m, n) == 20);
assert(GCD(m, n) == GCD(n,m));
And the same for add_fractions and reduce_fraction, as well :)
I'm trying to implement the Matlab fft2() function in C using the FFTW3 library.
However, I've got different results.
Considering a matrix [1 2; 3 4], the result with Matlab fft2 is [10 -2; -4 0] and with FFTW3
[10 -2; (3.05455e-314 + 2.122e-314i) (9.31763e-315 + 9.32558e-315i)]
I used the following code:
fftw_plan planG;
fftw_complex *inG, *outG;
inG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * 2 * 2);
outG = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * 2 * 2);
inG[0][0]=1.0;
inG[1][0]=2.0;
inG[2][0]=3.0;
inG[3][0]=4.0;
inG[0][1]=0.0;
inG[1][1]=0.0;
inG[2][1]=0.0;
inG[3][1]=0.0;
planG = fftw_plan_dft_2d(2, 2, inG, outG, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(planG);
What am I doing wrong?
Thanks in advance.
It seems to work OK for me:
// fftw_test.c
#include <stdio.h>
#include <fftw3.h>
int main(int argc, char * argv[])
{
fftw_plan planG;
fftw_complex *inG, *outG;
inG = fftw_malloc(sizeof(fftw_complex) * 2 * 2);
outG = fftw_malloc(sizeof(fftw_complex) * 2 * 2);
inG[0][0] = 1.0; // real input
inG[1][0] = 2.0;
inG[2][0] = 3.0;
inG[3][0] = 4.0;
inG[0][1] = 0.0; // imag input
inG[1][1] = 0.0;
inG[2][1] = 0.0;
inG[3][1] = 0.0;
planG = fftw_plan_dft_2d(2, 2, inG, outG, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(planG);
printf("outg[0] = { %g, %g }\n", outG[0][0], outG[0][1]);
printf("outg[1] = { %g, %g }\n", outG[1][0], outG[1][1]);
printf("outg[2] = { %g, %g }\n", outG[2][0], outG[2][1]);
printf("outg[3] = { %g, %g }\n", outG[3][0], outG[3][1]);
return 0;
}
Compile and run:
$ gcc -Wall -lfftw3 fftw_test.c -o fftw_test
$ ./fftw_test
outg[0] = { 10, 0 }
outg[1] = { -2, 0 }
outg[2] = { -4, 0 }
outg[3] = { 0, 0 }
$
I'm wondering if it's just that the code you're using to display the results is incorrect ?
For the 3x3 case I'm also getting matching:
// fftw_test_3_x_3.c
#include <stdio.h>
#include <fftw3.h>
#define M 3
#define N 3
int main(int argc, char * argv[])
{
fftw_plan planG;
fftw_complex *inG, *outG;
int i;
inG = fftw_malloc(sizeof(fftw_complex) * M * N);
outG = fftw_malloc(sizeof(fftw_complex) * M * N);
for (i = 0; i < M * N; ++i)
{
inG[i][0] = (double)(i + 1);
inG[i][1] = 0.0; // imag input
}
planG = fftw_plan_dft_2d(M, N, inG, outG, FFTW_FORWARD, FFTW_ESTIMATE);
fftw_execute(planG);
for (i = 0; i < M * N; ++i)
{
printf("outg[%d] = { %g, %g }\n", i, outG[i][0], outG[i][1]);
}
return 0;
}
Compile and run:
$ gcc -Wall -lfftw3 fftw_test_3_x_3.c -o fftw_test_3_x_3
$ ./fftw_test_3_x_3
outg[0] = { 45, 0 }
outg[1] = { -4.5, 2.59808 }
outg[2] = { -4.5, -2.59808 }
outg[3] = { -13.5, 7.79423 }
outg[4] = { 0, 0 }
outg[5] = { 0, 0 }
outg[6] = { -13.5, -7.79423 }
outg[7] = { 0, 0 }
outg[8] = { 0, 0 }
$
Compare with Octave (MATLAB clone):
octave:1> a = [1 2 3 ; 4 5 6 ; 7 8 9]
a =
1 2 3
4 5 6
7 8 9
octave:2> b = fft2(a, 3, 3)
b =
45.00000 + 0.00000i -4.50000 + 2.59808i -4.50000 - 2.59808i
-13.50000 + 7.79423i 0.00000 + 0.00000i 0.00000 + 0.00000i
-13.50000 - 7.79423i 0.00000 - 0.00000i 0.00000 - 0.00000i
octave:2>
Your code looks correct. I tried it with GCC gcc-4_7-branch revision 189773 on a 64bit machine, and it is returning
10 -2
-4 0
as it should.
Also tried different output techniques with printf formats (%f, %g, %lg), and accessing data with creal for good measure -- it is always returning the expected results.
Are you using GCC with quad_precision enabled? That's one of the things I can't test now.