Reputation: 33
I have been trying to translate some MATLAB code into C but one particular function is giving me different results between the two languages. I don't think it is a precision error because the values of the variables aren't astonishingly big or small. I will post code now and then provide information about the values of the variables:
Preproccesor directives (this file is linked):
#include "ff_addfunc.h"
#include <stdio.h>
#include <stdlib.h>
//#include <complex.h> (already included in the header file)
#include <math.h>
#ifndef HBAR
#define HBAR 1
#endif
#ifndef SPRING_CONST
#define SPRING_CONST 1
#endif
#ifndef PI
#define PI 3.14159265359
#endif
Immediately below is the problem function in C and below that is the same function in MATLAB. All numerical results match between the two before this function is called. What I find is when x1 == x2
, MATLAB and C agree on the result; but when x1 != x2
, C returns a slightly different result of which I will show below. This means that the arithmetic to the left of the minus sign is causing the problem.
Here is the C code:
double lagrangian(double x1,double x2,double dt,double m) {
return 1/2*m*(x2-x1)*(x2-x1)/dt/dt-SPRING_CONST*(x2*x2+x1*x1)/4;
}
Here is the MATLAB equivalent:
function L = Lagrangian(x1,x2,dt,m)
k = 1;
L = 1/2*m*(x2-x1).^2./dt.^2-k*(x2.^2+x1.^2)/4;
What I find is if I have x1 = -4
, x2 = -3.986667
, dt = 0.049087
, and m = 1
the C function returns -7.973378
while MATLAB gives me -7.9365
. Now, the reason why I am putting this down as a problem in C rather than MATLAB is because I was able to verify the MATLAB number using google as a calculator.
I compiled using gcc since g++ was complaining at me for using #include<complex.h>
instead of #include<complex>
.
Could anyone tell me why this is and how I can correct it? If there are any questions or if you need to see more code, let me know.
Other notes (none resulting in a change):
pow()
instead of (x2-x1)*(x2-x1)
Upvotes: 1
Views: 351
Reputation: 283624
The direct translation would be:
0.5*m*(x2-x1)*(x2-x1)/(dt*dt)-SPRING_CONST*(x2*x2+x1*x1)/4;
(Fixed integer division and grouping of the dt
terms)
Upvotes: 1
Reputation: 16305
I used:
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#ifndef HBAR
#define HBAR 1.0
#endif
#ifndef SPRING_CONST
#define SPRING_CONST 1.0
#endif
#ifndef PI
#define PI 3.14159265359
#endif
double lagrangian(double x1,double x2,double dt,double m) {
return 1.0/2.0*m*(x2-x1)*(x2-x1)/dt/dt-SPRING_CONST*(x2*x2+x1*x1)/4.0;
}
int
main(void)
{
printf("l: %g\n", lagrangian(-4,-3.986667,0.049087,1));
return 0;
}
and got:
l: -7.93649
I think your non-double
constants are goofing up your calculation. In fact just replacing
1.0/2.0*m...
with
1/2*m...
reproduced your erroneous value for me.
Upvotes: 1
Reputation: 239011
In C, /
and *
have equal precedence and associate left-to-right. This means that in this subexpression:
1/2*m*(x2-x1)*(x2-x1)/dt/dt
the subexpression 1/2
is grouped. Because both 1
and 2
are int
constants, this is an integer division - which is truncating. 1/2
is always just zero in C, so this entire subexpression becomes zero.
Use 1.0/2.0
(or just 0.5
) instead.
Upvotes: 1