C++ 如果(a==b)不';t在for循环中为双打工作

C++ 如果(a==b)不';t在for循环中为双打工作,c++,for-loop,C++,For Loop,我目前正试图编写一个滴定曲线模拟器。但我在比较两个值时遇到了一些麻烦 我创建了一个小的工作示例,完美地复制了我遇到的bug: #include <iostream> #include <math.h> using namespace std; int main() { double a, b; a = 5; b = 0; for(double i = 0; i<=(2*a); i+=0.1){ b = i;

我目前正试图编写一个滴定曲线模拟器。但我在比较两个值时遇到了一些麻烦

我创建了一个小的工作示例,完美地复制了我遇到的bug:

#include <iostream>
#include <math.h>

using namespace std;

int main()
{
    double a, b;
    a = 5;
    b = 0;
    for(double i = 0; i<=(2*a); i+=0.1){
        b = i;
        cout << "a=" << a << "; b="<<b;
        if(a==b)
            cout << "Equal!" << endl;
        else
            cout << endl;
    }
    return 0;
}
但是,如果我将迭代增量从
I+=0.1
更改为
I+=1
I+=0.5
,我将得到

a=5; b=5Equal!
如你所料


我在linux上使用g++进行编译,没有使用更多的标志,坦率地说,我不知道如何解决这个问题。非常感谢任何指针(甚至是我问题的完整解决方案)。

浮点算法是。。。有趣。在大多数语言中,用浮点/双精度测试等式都很烦人,因为它是在IEEE浮点数学中进行的。基本上,如果您可以将表达式计算为5.0,编译器可能会将其计算为4.9999999,因为它是IEEE标准中最接近的可表示数字

因为这些数字略有不同,所以最终会出现一个不等式。因为试图预测编译时将看到的数字是不可维护的,所以您不能/不应该尝试将它们中的任何一个硬编码到源代码中,以测试它们是否相等。作为一项硬性规定,避免直接检查浮点数的相等性

相反,测试它们是否非常接近与以下内容相等:

template<typename T>
bool floatEqual(const T& a, const T& b) {
  auto delta = a * 0.03;
  auto minAccepted = a - delta;
  auto maxAccepted = a + delta;
  return b > minAccepted && b < maxAccepted;
}
模板
布尔浮式码头(施工T&a、施工T&b){
自动增量=a*0.03;
自动minAccepted=a-增量;
自动最大接受=a+增量;
返回b>minAccepted&&b

这将检查b是否在a值的+3%或-3%范围内。

浮点运算是。。。有趣。在大多数语言中,用浮点/双精度测试等式都很烦人,因为它是在IEEE浮点数学中进行的。基本上,如果您可以将表达式计算为5.0,编译器可能会将其计算为4.9999999,因为它是IEEE标准中最接近的可表示数字

因为这些数字略有不同,所以最终会出现一个不等式。因为试图预测编译时将看到的数字是不可维护的,所以您不能/不应该尝试将它们中的任何一个硬编码到源代码中,以测试它们是否相等。作为一项硬性规定,避免直接检查浮点数的相等性

相反,测试它们是否非常接近与以下内容相等:

template<typename T>
bool floatEqual(const T& a, const T& b) {
  auto delta = a * 0.03;
  auto minAccepted = a - delta;
  auto maxAccepted = a + delta;
  return b > minAccepted && b < maxAccepted;
}
模板
布尔浮式码头(施工T&a、施工T&b){
自动增量=a*0.03;
自动minAccepted=a-增量;
自动最大接受=a+增量;
返回b>minAccepted&&b

这将检查b是否在a值的+3%或-3%范围内。

与整数不同,将浮点/双精度相乘并将它们相加不会产生完全相同的结果

因此,最好的做法是找出它们之间差异的
abs
是否足够小

如果您对数字的大小有所了解,可以使用常数:

if (fabs(a - b) < EPS) // equal
注:
在代码中,可以使用
std::abs
。对于
std::min/max
相同。使用C函数时,代码更清晰/更短。

与整数不同,将浮点/双精度相乘并将它们相加不会产生完全相同的结果

因此,最好的做法是找出它们之间差异的
abs
是否足够小

如果您对数字的大小有所了解,可以使用常数:

if (fabs(a - b) < EPS) // equal
注:
在代码中,可以使用
std::abs
。对于
std::min/max
相同。使用C函数时,代码更清晰/更短。

我建议重新构造循环,使用整数进行迭代,然后将整数转换为双精度,如下所示:

double step = 0.1;

for(int i = 0; i*step<=2*a; ++i){
    b = i*step;
    cout << "a=" << a << "; b="<<b;
    if(a==b)
        cout << "Equal!" << endl;
    else
        cout << endl;
}
double step=0.1;

对于(int i=0;i*step,我建议重新构造循环,使用整数进行迭代,然后将整数转换为双精度,如下所示:

double step = 0.1;

for(int i = 0; i*step<=2*a; ++i){
    b = i*step;
    cout << "a=" << a << "; b="<<b;
    if(a==b)
        cout << "Equal!" << endl;
    else
        cout << endl;
}
double step=0.1;

对于(int i=0;i*step.不要在循环条件中使用浮点数…
1.0
0.5
可以使用浮点数表示为有限的精确数字。
0.1
另一方面只能由无限浮点数表示,当存储在有限浮点数中时会暴露舍入错误ber.This:@OliCharlesworth,摘自首页:“也许你在某个论坛上寻求帮助,但被指向了一个似乎对你的问题没有帮助的网站。”-猜猜那个链接指向哪里;)。不要在循环条件中使用浮点…
1.0
0.5
可以使用浮点数表示为有限的精确数字。
0.1
则只能表示为无限的浮点数,当存储在有限的浮点数中时会暴露舍入错误。这:@OliCharLeVals:从“首页”中可以看出:“也许你在某个论坛上寻求帮助,并指出了一个似乎没有帮助你解决问题的问题。”——猜猜链接指向哪里;)算术定义得很好,在实现标准的所有实现(大多数C++编译器都是)上是可预测的。@IInspectable-有趣。谢谢!我对结果比对原因更感兴趣,但我还是更新了帖子。坏例子:5.0在IEEE 754中是可表示的。4.999999不是。问题包含另一个不可表示的数字0.1。算术定义良好,在所有实现标准的实现中都是可预测的D(大多数C++编译器)“IsCuffTime-有趣的是,我对结果比对这个原因更感兴趣,但是我更新了帖子。坏的例子是IEEE 754中的5。4.9999999是不包含的。这个问题包含另一个不可代表的数字,0.1为什么不使用<代码> STD::ABS<代码>?它在C++中浮点类型过载。STD::ABS是al。很好,代码是l