Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/134.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 浮点比较的奇怪结果_C++_Floating Point - Fatal编程技术网

C++ 浮点比较的奇怪结果

C++ 浮点比较的奇怪结果,c++,floating-point,C++,Floating Point,我有一个简单的测试: double h; ... // code that assigns h its initial value, used below ... if ((h>0) && (h<1)){ //branch 1 -some computations } else{ //branch 2- no computations } } 编辑: 好的,很清楚我应该如何重新定义这个条件 发件人: 致: 双h; if(abs(h-1)由于h是一个双精度值,它

我有一个简单的测试:

double h;
...
// code that assigns h its initial value, used below
...
if ((h>0) && (h<1)){
 //branch 1 -some computations
}
else{
 //branch 2- no computations
}
}


编辑: 好的,很清楚我应该如何重新定义这个条件

发件人:

致:

双h;

if(abs(h-1)由于
h
是一个双精度值,它可能已经接近1,可以打印为
1
,但实际上它比1小一点,所以比较成功。经常这样做。

这可能是一个精度问题。h可能不完全是1,但非常接近它。您能否发布一些关于您尝试执行的操作的更多信息,例如:例如,H的值从何而来,又从何而来?

如果必须在检查中使用浮点数,请将其舍入并存储在例如整数中。
1f可以是1.0000000000000001或0.999999999999999999999999999999999999999999999999999999999999999999999检查h的实际值。您可能会发现它实际上略小于1.0

我运行了以下代码作为测试

#include <iostream>

int main()
{
    double h = 1.0;
    if((h>0) && (h<1))
    {
        std::cout << "first branch" << std::endl;
    }
    else
    {
        std::cout << "second branch" << std::endl;
    }
}
请注意,在这种特殊情况下“(h-0.0)”可以替换为“h”。为了便于说明,我将其保留原样


另外请注意,如果只进行一次比较,则需要将增量与h和某个常数之间差值的绝对值进行比较。由于您在此处检查一个范围,因此这两次比较和一起构成一种特殊情况,您可以绕过使用
abs
。如果h是负值或某个正值如果大于1.0,它将超出范围,并且无法通过上述两个测试中的一个。

这可能与C/C++中的双精度是64位有关,但计算可以以更高的精度进行(cpu的浮点寄存器更宽(96位),因此,即使像cos(x)==cos(x)这样的语句也不可能是真的


参考资料:

原因是浮点数不是保存在变量中的数字的实数表示形式。(与BCD[二进制编码的小数]相反)

您可以在此处看到定义:

所以问题是某些数字不能用一组给定的位来表示 诀窍在于,在大多数情况下,保存的数字与预期数字之间的差异非常小。实际上,在某些情况下,这可能会导致问题。 例如,这就是为什么你不应该建立一个金融软件并使用浮点数进行货币计算的原因。你很容易会有明显的差异,这是你的税务局不喜欢的

因此,要比较浮点数,您应该始终应用某种适用于您的应用程序的阈值。例如:

if(a==b) 
变成

if(abs(a-b)<threshold)

if(abs(a-b)在比较浮点值时始终允许舍入错误。与测试相等性不同,您通常希望这样做:

if (abs(x - y) < epsilon) ...
if(abs(x-y)
式中,ε是一些适当的小值,如0.00001

浮点数学不准确有几个原因。首先,并非所有值都能精确表示(例如,0.1不能用二进制浮点数表示,就像1/3不能用小数表示一样)


另一种是浮点只使用固定数量的有效数字(相对于小数点“浮动”,因此得名)。因此,对于大数字,小分数实际上会被截断。永远不要假设浮点计算会返回准确的结果。

简而言之:您的测试是不正确的,因为浮点数字的行为与您可能期望的不一样。特别是像“denom==0”这样的东西是有问题的

Sun很好地在线提供了这篇文章:

这和广告上说的一模一样。根据你的背景,这将是一本易读的书,或者是一个很大的工作,但是对于任何使用浮动的程序员来说,这确实是值得的

补充评论:我并不是说每个程序员都能很容易地理解那篇文章中的所有内容。但仔细阅读它至少会更好地了解什么是浮动,什么是问题,以及如何正确处理问题的一些提示


如果你想正确地做大量的数值计算,你必须阅读各种技术,但那将是一本(或几本)教科书有价值的资料。这里的评论已经指出了一些基础知识,并链接到了更多的内容。好的,你已经发布了代码。你通过一系列看起来相当任意的数字的算术运算来计算h。这意味着你将得到非常接近理想值h的近似值,但不完全是r好的


这意味着您需要进行近似比较。测试(h==1.0)只有在偶然情况下才会成功;尝试(fabs(h-1.0)<1e-10)或类似的方法(使用常数双精度而不是用于公差的幻数)。对其他比较进行适当的更改。

您可能对(又名“EPSILON不是0.00001!”)在GDC 2005上发表的演讲。

我不认为是这样,因为1.0通常表示为1(指数和尾数为0)在浮点位中。@leppie:and.99999999在大多数默认打印函数中打印为1。and.999999999<1是一个true语句。如果h的值实际上为1,则该条件将失败。打印值和实际值不相同,但给定1的输入转换为双精度(IEEE 754)正好是1点。00000000000000000000000000000000000000000000000000000000000000@leppie:但如果h是计算出的双精度,其值为0.99999999,则打印时可能显示为1.0,但它将正确计算为<1。我看不出OP在哪里说“当h打印1”,而不是说“当h=1”@madalina:要确定它是否真的是1.0,或者只是打印为1.0,请尝试在if之前分配h=1.0,然后查看哪个分支会被接受
#include <iostream>

int main()
{
    double h = 1.0;
    if((h>0) && (h<1))
    {
        std::cout << "first branch" << std::endl;
    }
    else
    {
        std::cout << "second branch" << std::endl;
    }
}
double allowedDelta = 0.000001;

if( ((h - 0.0) > allowedDelta) && ((1.0 - h) > allowedDelta) )
... // h is between 0.000001 and 0.9999990
if(a==b) 
if(abs(a-b)<threshold)
if(a<1)
if(a < 1-threshold)
if (abs(x - y) < epsilon) ...