matlab和c的区别在于cos函数
我有一个用matlab实现的程序和用c实现的相同程序,但结果不同。
我有点困惑 cos 函数没有返回完全相同的结果。
在这两种情况下,我都使用同一台计算机、Intel Core 2 Duo 和 8 字节双精度数据类型。
为什么结果不同?
测试如下:
c:
double a = 2.89308776595231886830;
double b = cos(a);
printf("a = %.50f\n", a);
printf("b = %.50f\n", b);
printf("sizeof(a): %ld\n", sizeof(a));
printf("sizeof(b): %ld\n", sizeof(b));
a = 2.89308776595231886830106304842047393321990966796875
b = -0.96928123535654842068964853751822374761104583740234
sizeof(a): 8
sizeof(b): 8
matlab:
a = 2.89308776595231886830
b = cos(a);
fprintf('a = %.50f\n', a);
fprintf('b = %.50f\n', b);
whos('a')
whos('b')
a = 2.89308776595231886830106304842047393321990966796875
b = -0.96928123535654830966734607500256970524787902832031
Name Size Bytes Class Attributes
a 1x1 8 double
Name Size Bytes Class Attributes
b 1x1 8 double
So, b differ a bit (very slightly, but enough to make my debuging task difficult)
b = -0.96928123535654842068964853751822374761104583740234 c
b = -0.96928123535654830966734607500256970524787902832031 matlab
我使用同一台计算机,Intel Core 2 Duo,8 字节双精度数据类型。
为什么结果不同?
matlab不使用Intel内置的cos函数硬件吗?
有没有一种简单的方法可以在 matlab 和 c 中使用相同的 cos 函数(具有精确的结果),即使速度慢一点,以便我可以安全地比较我的 matlab 和 c 程序的结果?
更新:
非常感谢您的回答!
因此,正如您所指出的,matlab 和 c 的 cos 函数不同。 太棒了!我以为他们使用的是英特尔微处理器内置的 cos 函数。
matlab 的 cos 版本与 matlab 的版本相同(至少对于本次测试)。 你也可以从 matlab 尝试: b=java.lang.Math.cos(a)
然后,我做了一个小的 MEX 函数来使用 matlab 中的 cos c 版本,它工作得很好;这使我能够调试我的程序(在 matlab 和 c 中实现的相同程序)并查看它们在哪些方面有所不同,这就是本文的目的。
唯一的问题是从 matlab 调用 MEX c cos 版本太慢了。
我现在尝试从 c 调用 Java cos 函数(因为它与 matlab 中的函数相同),看看是否会更快。
I have a program implemented in matlab and the same program in c, and the results differ.
I am bit puzzled that the cos function does not return the exact same result.
I use the same computer, Intel Core 2 Duo, and 8 bytes double data type in both cases.
Why does the result differ?
Here is the test:
c:
double a = 2.89308776595231886830;
double b = cos(a);
printf("a = %.50f\n", a);
printf("b = %.50f\n", b);
printf("sizeof(a): %ld\n", sizeof(a));
printf("sizeof(b): %ld\n", sizeof(b));
a = 2.89308776595231886830106304842047393321990966796875
b = -0.96928123535654842068964853751822374761104583740234
sizeof(a): 8
sizeof(b): 8
matlab:
a = 2.89308776595231886830
b = cos(a);
fprintf('a = %.50f\n', a);
fprintf('b = %.50f\n', b);
whos('a')
whos('b')
a = 2.89308776595231886830106304842047393321990966796875
b = -0.96928123535654830966734607500256970524787902832031
Name Size Bytes Class Attributes
a 1x1 8 double
Name Size Bytes Class Attributes
b 1x1 8 double
So, b differ a bit (very slightly, but enough to make my debuging task difficult)
b = -0.96928123535654842068964853751822374761104583740234 c
b = -0.96928123535654830966734607500256970524787902832031 matlab
I use the same computer, Intel Core 2 Duo, and 8 bytes double data type.
Why does the result differ?
does matlab do not use the cos function hardware built-in in Intel?
Is there a simple way to use the same cos function in matlab and c (with exact results), even if a bit slower, so that I can safely compare the results of my matlab and c program?
Update:
thanks a lot for your answers!
So, as you have pointed out, the cos function for matlab and c differ.
That's amazing! I thought they were using the cos function built-in in the Intel microprocessor.
The cos version of matlab is equal (at least for this test) to the one of matlab.
you can try from matlab also: b=java.lang.Math.cos(a)
Then, I did a small MEX function to use the cos c version from within matlab, and it works fine; This allows me to debug the my program (the same one implemented in matlab and c) and see at what point they differ, which was the purpose of this post.
The only thing is that calling the MEX c cos version from matlab is way too slow.
I am now trying to call the Java cos function from c (as it is the same from matlab), see if that goes faster.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
浮点数以二进制存储,而不是十进制存储。双精度浮点数具有 52 位精度,大约转换为 15 位有效小数。换句话说,以十进制打印的
double
的前 15 个非零十进制数字足以唯一确定打印的是哪个double
。作为二元有理,
double
具有精确 的十进制表示形式,它需要比 15 多得多的小数位来表示(在您的情况下,我相信有 52 或 53 个地方)。然而,printf
和类似函数的标准并不要求第 15 位之后的数字是正确的;它们可能完全是无稽之谈。我怀疑这两个环境之一正在打印精确值,另一个环境正在打印较差的近似值,而实际上两者都对应于完全相同的二进制double
值。Floating point numbers are stored in binary, not decimal. A
double
precision float has 52 bits of precision, which translates to roughly 15 significant decimal places. In other words, the first 15 nonzero decimal digits of adouble
printed in decimal are enough to uniquely determine whichdouble
was printed.As a diadic rational, a
double
has an exact representation in decimal, which takes many more decimal places than 15 to represent (in your case, 52 or 53 places, I believe). However, the standards forprintf
and similar functions do not require the digits past the 15th to be correct; they could be complete nonsense. I suspect one of the two environments is printing the exact value, and the other is printing a poor approximation, and that in reality both correspond to the exact same binarydouble
value.使用 http://www.mathworks.com/matlabcentral 中的脚本/fileexchange/1777-from-double-to-string
两个数字之间的差异仅在最后一位:
其中一个必须更接近“正确”答案,假设给定的值
a
是准确的。所以,C库的结果更加准确。
然而,就您的问题而言,您不应期望在 matlab 以及您链接的任何 C 库中得到相同的答案。
Using the script at http://www.mathworks.com/matlabcentral/fileexchange/1777-from-double-to-string
the difference between the two numbers is only in the last bit:
One of them must be closer to the "correct" answer, assuming the value given for
a
is exact.So, the C library result is more accurate.
For the purposes of your question, however, you should not expect to get the same answer in matlab and whichever C library you linked with.
结果在小数点后 15 位以内都是相同的,我怀疑这对于几乎所有应用程序来说都足够了,如果您需要更多,您可能应该实现您自己的余弦版本,这样您就可以控制细节并且您的代码是可移植的跨不同的 C 编译器。
它们会有所不同,因为它们无疑使用不同的方法来计算结果的近似值或迭代不同的次数。由于余弦被定义为无限系列的项,因此必须在其软件实现中使用近似值。 CORDIC 算法是一种常见的实现。
不幸的是,我不知道这两种情况下的实现细节,实际上 C 实现将取决于您正在使用的 C 标准库实现。
The result is the same up to 15 decimal places, I suspect that is sufficient for almost all applications and if you require more you should probably be implementing your own version of cosine anyway such that you are in control of the specifics and your code is portable across different C compilers.
They will differ because they undoubtedly use different methods to calculate the approximation to the result or iterate a different number of times. As cosine is defined as an infinite series of terms an approximation must be used for its software implementation. The CORDIC algorithm is one common implementation.
Unfortunately, I don't know the specifics of the implementation in either case, indeed the C one will depend on which C standard library implementation you are using.
正如其他人所解释的,当您直接在源代码中输入该数字时,不会使用所有小数位,因为您只能获得 15/16 位小数的精度。事实上,它们被转换为最接近的二进制双精度值(超出固定数字限制的任何内容都会被丢弃)。
更糟糕的是,根据 @R ,IEEE 754 在使用余弦函数时容忍最后一位的错误。我实际上在使用不同的编译器时遇到了这个问题。
为了说明这一点,我使用以下 MEX 文件进行了测试,使用默认的 LCC 编译器进行编译,然后使用 VS2010(我使用的是 WinXP 32 位)。
在一个函数中,我们直接调用 C 函数(
mexPrintf
只是一个宏#define
作为printf
)。另一方面,我们调用mexEvalString
来评估 MATLAB 引擎中的内容(相当于使用 MATLAB 中的命令提示符)。prec.c
LCC
copmiled 与使用 VS2010 编译的
我使用以下命令编译上述内容:
mex -v -largeArrayDims prec.c
,并使用以下命令在后端编译器之间切换:mex -setup
我还尝试打印数字的十六进制表示形式。我只设法在 C 中显示二进制双精度数的下半部分(也许您可以使用某种位操作获得另一半,但我不确定如何!)
最后,如果您需要更精确的计算,请考虑使用可变精度算术库。在 MATLAB 中,如果您可以访问符号数学工具箱,请尝试:
这样您就可以看到实际值介于我上面得到的两个不同近似值之间,而且事实上它们都相等直到小数点后 15 位:
更新:
如果您想在 C 中正确显示浮点数的十六进制表示形式,请改用此辅助函数(类似于 MATLAB 中的 NUM2HEX 函数):
As others have explained, when you enter that number directly in your source code, not all the fraction digits will be used, as you only get 15/16 decimal places for precision. In fact, they get converted to the nearest double value in binary (anything beyond the fixed limit of digits is dropped).
To make things worse, and according to @R, IEEE 754 tolerates error in the last bit when using the cosine function. I actually ran into this when using different compilers.
To illustrate, I tested with the following MEX file, once compiled with the default LCC compiler, and then using VS2010 (I am on WinXP 32-bit).
In one function we directly call the C functions (
mexPrintf
is simply a macro#define
asprintf
). In the other, we callmexEvalString
to evaulate stuff in the MATLAB engine (equivalent to using the command prompt in MATLAB).prec.c
copmiled with LCC
compiled with VS2010
I compile the above using:
mex -v -largeArrayDims prec.c
, and switch between the backend compilers using:mex -setup
Note that I also tried to print the hexadecimal representation of the numbers. I only managed to show the lower half of binary double numbers in C (perhaps you can get the other half using some sort of bit manipulations, but I'm not sure how!)
Finally, if you need more precision in you calculations, consider using a library for variable precision arithmetic. In MATLAB, if you have access to the Symbolic Math Toolbox, try:
So you can see that the actual value is somewhere between the two different approximations I got above, and in fact they are all equal up to the 15th decimal place:
UPDATE:
If you want to correctly display the hexadecimal representation of floating point numbers in C, use this helper function instead (similar to NUM2HEX function in MATLAB):