使用 float / double 作为循环变量

Using float / double as a loop variable

运行 在 x64 架构上,Visual Studio 2013 Windows 8.1

我正在尝试 运行 一个使用浮点数作为其循环变量的循环,问题是在递增操作期间,十进制值正在丢失。

例如:

float incrementValue = 360 / 14;
for (float i = 0; i <= 360; i = i + incrementValue)
{
    cout << endl << " I " << i;
}

我需要 i >= 360 的值。但它停在 350 。 由于 360/14 =25.7142857 但看起来增量是以 25 为步长的。 如果我对任何整数做同样的事情它都可以正常工作,这个问题只适用于 xx.yyyy

形式的任何数字

我尝试查找有关此问题的各种网站,但找不到任何可以帮助我/回答我问题的内容。

360 / 14 会给你一个整数结果。试试 360.0 / 14.0.

你这里有三个问题(两个相关),所有这些问题都可能有贡献。

首先是浮点数比较通常是不明智的,因为虽然您可能 认为 您有 360,但实际上可能是 359.999999942

第二个是随着时间的推移会出现不准确的情况。每次添加像 0.99 这样的数字时,您 认为 1,错误就会累积。

根据您使用的值,这些错误可能会保持很小,但无论如何您都应该注意它们。如果您开始处理大量数字,您会很快发现问题所在。


最后一个不相关的问题是 360 / 14 整数 除法,它会给你一个整数结果,25 而不是 25.714285714.

您可以通过确保其中一个值是浮点数来解决最后一个问题:

float incrementValue = float(360) / 14;

但这并不能解决前两个问题,在某些时候咬你。

要修复那个,你最好坚持使用整数(无论如何对于这个简单的情况)并在最新的可能实例中转换为浮点数:

#include<iostream>
int main (void) {
    int incrementValue = 360;
    for (int i = 0; i <= 360 * 14; i = i + incrementValue)
        std::cout << " I " << float(i) / 14 << '\n';
    return 0;
}

这给你:

 I 0
 I 25.7143
 I 51.4286
 I 77.1429
 I 102.857
 I 128.571
 I 154.286
 I 180
 I 205.714
 I 231.429
 I 257.143
 I 282.857
 I 308.571
 I 334.286
 I 360

将除法的操作数设为浮点型:

 float incrementValue = 360.f / 14.f;
  float incrementValue = (float)360 / 14;
  for (float i = 0; i <= 360; i = i + incrementValue)
  {
      cout << endl << " I " << i;
  }

很难获得 'i = 360',因为 'i = 360.0000001' 将无法通过测试并且准确获得“360”将很棘手。计算机上的浮点数很难,而且充满了小问题。

尽量使用整数比较好:-

int num_steps = 14;

for (int i = 0 ; i <= num_steps ; ++i)
{
  float value = 360.0f * i / num_steps;
  // use value
}

在循环中使用“<=”确实意味着您得到 'value' 的“360”,因为 'i / num_steps' 是一个。话虽如此,由于浮点错误,您可能无法准确获得“360.0f”。

如果您知道迭代次数,那么使用浮点数来控制循环不是一个好主意,因为浮点数并不精确。

事实上,如果不使用公差(取决于机器精度)来考虑潜在的舍入误差,使用浮点数来控制任何循环都是一个坏主意。

在这种情况下,您知道迭代次数,因此像这样的循环就可以解决问题。

int num_steps = 14
float factor = 360.0/num_steps;

for (int i = 0; i < num_steps; ++i)
{
    std::cout << "\nI" << (i*factor);
}

当我真的想在我的循环中使用浮点数时,我会更改上限以确保我不会因连续的浮点错误而出错。

float x_min = 0.;
float x_max = 360.;
int N_steps = 14;
float x_step = (x_max - x_min) / N_steps;

for (float x = x_min; x <= x_max + x_step / 2; x += x_step)
{
    // do stuff
}

虽然这可以确保我的每一步都是正确的,但如果有大量的步骤,精度问题就会增加。在那种情况下,使用整数循环变量并每次计算相应的浮点数。然后我只有一次浮点错误,而不是总结 14(或一百万)次。