java - C/C++ 双数算术表达式 - 奇怪的结果 - 用 java 翻译

标签 java c++ c double arithmetic-expressions

第一个问题

在 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 。

一般来说,两个数字 123e4561.23e458(以浮点 IEEE 754 二进制格式表示时)仍然会有所不同,尽管在数学上是不同的他们绝对平等。

关于java - C/C++ 双数算术表达式 - 奇怪的结果 - 用 java 翻译,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32771276/

相关文章:

c++ - QMessageBox 在关闭时删除

c++ - 快速排序(n 个数组应被视为 1 并根据需要重新映射值)

java - 在 IntegrationFlow 服务激活器方法成功返回之前不确认 RabbitMQ 消息?

java - 控制 Java Swing 布局中的文本框高度

c++ - GCC 内联 C++ 函数是否没有 'inline' 关键字?

c++ - 加载c++ dll文件时如何修复EXCEPTION_ACCESS_VIOLATION?

c - Apache 模块创建教程包含有错误的代码。怎么修?

c - 是什么 | 0x01用C语言做什么?

JavaFX8 - FXML 如何在 onAction-tag 中使用参数调用方法?

java - Windows 10 上的 Tizen Install 无法识别已安装的 JDK 9