第一个问题
在 C 代码中我有这个表达式:
double completeExpression = x1 - h*exp(-lambda*t);
我将其分为两个操作:
double value = h*exp(-lambda*t);
double subtraction = x1 - value;
问题在于减法与completeExpression不同。 怎么了?
我用以下几行在我的代码中重现了一个奇怪的结果:
const double TOLERANCE = 1e-16;
double h = 0.51152525298500628;
double lambda =0.99999999999999978;
double t=0.1;
double x1 =0.4628471891711442 ;
double completeExpression = x1 - h*exp(-lambda*t);
double value = h*exp(-lambda*t);
double subtraction = x1 - value;
printf("x1 = %1.4e & value = %1.4e",x1,value);
printf("\ncompleteExpression = %1.4e",completeExpression);
printf("\nsubtraction = %1.4e",subtraction);
结果:
x1 = 4.6285e-001 & value = 4.6285e-001
completeExpression = 8.2779e-017
subtraction = 5.5511e-017
<小时/>
第二个问题:
我必须用Java翻译completeExpression,并且我总是返回错误的结果(减法)而不是completeExpression值:
代码:
static double TOLERANCE = 1e-16;
public static void main() {
double h = 0.51152525298500628;
double lambda =0.99999999999999978;
double t=0.1;
double x1 =0.4628471891711442 ;
double completeExpression = x1 - h*Math.exp(-lambda*t);
double value = h*Math.exp(-lambda*t);
double subtraction = x1 - value;
System.out.println( "x1 = " + String.format("%1.4e", value) + "& value = " + String.format("%1.4e",x1) );
System.out.println("\ncompleteExpression = " + String.format("%1.4e",completeExpression));
System.out.println("\nsubtraction = " + String.format("%1.4e",subtraction));
<小时/>
#gcc --version
My Gcc Version:
$ gcc --version
gcc.exe (GCC) 4.8.1
Copyright (C) 2013 Free Software Foundation, Inc.
This is free software; see the source for copying conditions. There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
最佳答案
float (与整数不同)几乎永远不会完全相同。原因在于它们的存储方式(尾数和指数)。
最终,在对两个 float 执行“相同”操作后,你永远无法确定它们是否相同。更重要的是 - if(subtraction!=completeExpression)
通常是无效的。相反,您应该寻找“接近的匹配”:
if( abs(subtraction - completeExpression) < TOLERANCE )
其中 TOLERANCE
是您拥有的一些常量,例如 const double TOLERANCE = 1e-16;
有关为什么 float “近似”的更多信息,您可以阅读浮点
上的Wiki。但根本原因是浮点值表示的数字范围远远大于给定空间可以编码的位数。
32位整数可以编码从-2GB到+2GB的值,但32位 float 的范围是从-3.4e38到+3.4e38。这是超过 20 位数字的范围差异!
对于 64 位值,范围差异甚至更大,几乎有 300 位数字。
扩展范围是有代价的 - 32 或 64 位空间的一部分用于表示“精度”数字(二进制,而不是十进制),而这些数字的数量限制了最终精度你的 float 。
一般来说,两个数字 123e456
和 1.23e458
(以浮点 IEEE 754 二进制格式表示时)仍然会有所不同,尽管在数学上是不同的他们绝对平等。
关于java - C/C++ 双数算术表达式 - 奇怪的结果 - 用 java 翻译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32771276/