简体   繁体   中英

C programming: translated function from MATLAB to C gives slightly (but significantly) different result

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):

  • I tried this on linux and on OS X (two different systems)
  • Tried pow() instead of (x2-x1)*(x2-x1)
  • Put the numbers into the C and MATLAB functions directly to account for any rounding in the displayed numbers I printed out
  • Printed out every input to make sure they were the same and checked that the correct data types were used

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.

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.

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)

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