【问题标题】:C programming: translated function from MATLAB to C gives slightly (but significantly) different resultC 编程:从 MATLAB 到 C 的翻译函数给出略微(但显着)不同的结果
【发布时间】:2013-05-17 00:44:32
【问题描述】:

我一直在尝试将一些 MATLAB 代码翻译成 C,但是一个特定的函数在两种语言之间给了我不同的结果。我不认为这是一个精度错误,因为变量的值并没有大得惊人或小得惊人。我将不时发布代码,然后提供有关变量值的信息:

Preproccesor 指令(此文件已链接):

#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

下面是 C 中的问题函数,下面是 MATLAB 中的相同函数。在调用此函数之前,两者之间的所有数值结果都匹配。我发现当x1 == x2、MATLAB 和 C 就结果达成一致时;但是当x1 != x2 时,C 返回的结果略有不同,我将在下面展示。这意味着减号左边的算术导致了问题。

这里是 C 代码:

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;
}

这是 MATLAB 等价物:

function L = Lagrangian(x1,x2,dt,m)

k = 1;
L = 1/2*m*(x2-x1).^2./dt.^2-k*(x2.^2+x1.^2)/4;

我发现如果我有 x1 = -4x2 = -3.986667dt = 0.049087m = 1,C 函数返回 -7.973378 而 MATLAB 给我 -7.9365。现在,我之所以将其归为 C 而不是 MATLAB 中的问题,是因为我能够使用 google 作为计算器来验证 MATLAB 编号。

我使用 gcc 编译,因为 g++ 抱怨我使用 #include&lt;complex.h&gt; 而不是 #include&lt;complex&gt;

谁能告诉我这是为什么以及如何纠正它?如果有任何问题或需要查看更多代码,请告诉我。

其他注释(没有导致更改):

  • 我在 linux 和 OS X(两个不同的系统)上试过这个
  • 尝试pow() 而不是(x2-x1)*(x2-x1)
  • 将数字直接放入 C 和 MATLAB 函数中,以说明我打印出的显示数字中的任何四舍五入
  • 打印出每个输入以确保它们相同,并检查是否使用了正确的数据类型

【问题讨论】:

  • matlab没有to-C编译器组件吗?此外,C 中的浮点类型并不准确,在算术运算尤其是除法之后容易累积很多错误。另外,使用1.0/2.0
  • 长话短说,不要使用原生 C 浮点数进行精确的科学计算。
  • 几乎可以肯定是浮点精度的差异。我的猜测是c版本使用单精度,而matlab版本使用双精度。
  • 它以纯文本表示他正在使用双精度浮点
  • 明显的起点:将1/2更改为1.0/2.0。 IMO,您可能应该发布您尝试实现的公式(以正常的数学表示法),以便我们可以验证您的 C 代码是否正确。

标签: c++ c matlab precision floating-accuracy


【解决方案1】:

直接翻译是:

0.5*m*(x2-x1)*(x2-x1)/(dt*dt)-SPRING_CONST*(x2*x2+x1*x1)/4;

(固定整数除法和dt 项的分组)

【讨论】:

    【解决方案2】:

    我用过:

    #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;
    }
    

    得到:

    l: -7.93649
    

    我认为您的非doubleconstants 正在搞砸您的计算。其实只是替换

    1.0/2.0*m...
    

    1/2*m...
    

    为我再现了你的错误价值。

    【讨论】:

    • 乘以 1/2 有问题...哎呀。这肯定会有很大的不同。
    • 仍然表明,与可能使用某种定点类型的 MATLAB 相比,使用浮点类型会引入错误。最重要的是,如果你想进行准确的数值计算,请不要在 C/C++ 中使用浮点类型。
    • 以不同的精度显示
    【解决方案3】:

    在 C 中,/* 具有相同的优先级并从左到右关联。这意味着在这个子表达式中:

    1/2*m*(x2-x1)*(x2-x1)/dt/dt
    

    子表达式1/2 被分组。因为12 都是int 常量,所以这是一个整数除法——它正在截断。 1/2 在 C 中总是为零,所以整个子表达式都为零。

    改用1.0/2.0(或只使用0.5)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多