for循环的问题(初学者)

Trouble with the for loop (Beginner)

本文关键字:初学者 问题 循环 for      更新时间:2023-10-16

我开始学习c++,我得到了这个简单的程序:(我提前为我的英语道歉)

#include <iostream>
#include <vector>
#include <string>
using namespace std;
vector<double> time_vector(int interval[], float increment)
{
    vector<double> time; 
    for (double i=interval[0]; i<=interval[1]; i=i+increment)
        time.push_back(i);
    return time;
}
int main(int argc, char** argv) {
    int interval[] = {0,3};
    float increment = 0.1;
    vector<double> time = time_vector(interval, increment);
    for (vector<double>::iterator it=time.begin(); it!=time.end(); ++it)
        cout << *it << " ";
    return 0;
}

time_vector函数的思想是创建一个范围为[a,b]的向量,并以一个增量值自增。这将模拟来自matlab

的命令
a:increment:b

但是当我运行它时,我得到这个:

0 0.1 0.2 0.3 0.4 0.5 0.6 0.7 0.8 0.9 1 1.1 1.2 1.3 1.4 1.5 1.6 1.7 1.8 1.9 2 2.1 2.2        2.3 2.4 2.5 2.6 2.7 2.8 2.9 0 

可以看到,最后一个元素不是3.0,而它应该是3.0。我这样做对吗?

很可能是浮点精度问题。参见浮点指南(每个程序员都应该知道的浮点算术)

因此0.1在IEEE754中不能完全表示

p。这不是c++本身的问题。在C、Ada或Fortran中也会遇到同样的问题。

这个问题与内部浮点表示有关:在for循环的最后一个循环中可能会发生以下情况

i = 2.9000000432133675
increment = 0.100000001
i + increment = 3.0000000442133675 

因此,条件不再满足,您将不会存储最后期望的结果。

你可能想在你的结果中添加一个epsilon值以确保正确性,例如

#include <iostream>
#include <vector>
#include <string>
using namespace std;
#define EPSILON 0.0000001
vector<double> time_vector(int interval[], float increment)
{
    vector<double> time; 
    for (double i=interval[0]; i<=interval[1] + EPSILON; i=i+increment)
        time.push_back(i);
    return time;
}
int main(int argc, char** argv) {
    int interval[] = {0,3};
    float increment = 0.1f;
    vector<double> time = time_vector(interval, increment);
    for (vector<double>::iterator it=time.begin(); it!=time.end(); ++it)
        cout << *it << " ";
    return 0;
}
http://ideone.com/WRi2ln

Nb。这并不意味着c++ 不如Matlab精确。Matlab内部处理所有这些技巧和权衡,但只是使它对您不透明,让您专注于其他事情(c++允许您做更多低级别的东西,但这是您为此付出的代价)。

由于浮点表示和您构建循环的方式,无法保证vector中存在范围内的最后一个数字。避免这种情况的一种方法是计算所需的步数来生成所需的范围并执行计算,如下所示:

std::vector<double> time_vector(int interval[], float increment)
{
    std::vector<double> time; 
    int nSteps = (int)((interval[1] - interval[0]) / increment + 0.5f); //Rounding
    time.push_back(interval[0]);
    for (int i = 1; i <= nSteps; ++i)
    {
        time.push_back(interval[0] + i * increment);
    }
    return time;
}

我注意到你在double、float和int之间做了很多隐式强制转换。而不是将间隔存储为两个整型,而是尝试将其存储为浮点数,您也可以将时间向量中的值增加一个浮点数,尽管它们存储为双精度。尝试使用统一类型,以便有列表隐式转换:

vector<float> time_vector(float interval[], float increment)
{
    vector<float> time; 
    for (float i=interval[0]; i<=interval[1]; i=i+increment)
        time.push_back(i);
    return time;
}
int main(int argc, char** argv) {
    float interval[] = {0,3};
    float increment = 0.1;
    vector<float> time = time_vector(interval, increment);
    for (vector<float>::iterator it=time.begin(); it!=time.end(); ++it)
        cout << *it << " ";
    return 0;
}