о сравнении чисел с плавающей точкой в C ++

0

У меня есть петля, чтобы зацикливать плавающее число между заданным диапазоном min и max, как следует

#include <iostream>
using namespace std;

void main(void)
{
  for (double x=0.012; x<=0.013; x+=0.001) 
  {
    cout << x << endl;
  }
}

Это довольно простой код, но, как я знаю на компьютерном языке, нам нужно сравнить два плавающих числа с рассмотренным EPS. Следовательно, выше код не работает (мы ожидаем, что он будет цикл два раза с 0,012 до 0,013, но он только цикл один раз). Поэтому я вручную добавляю EPS в верхний предел.

#include <iostream>
using namespace std;
#define EPS 0.0000001

void main(void)
{
  for (double x=0.012; x<=0.013+EPS; x+=0.001) 
  {
    cout << x << endl;
  }
}

и он работает сейчас. Но это выглядит безобразно, потому что EPS действительно зависит от машины. Я переношу свой код с matlab на C++, и у меня нет проблем в Matlab, так как есть команда eps. Но есть ли что-то подобное в C/C++?

Теги:
floating-point

1 ответ

3
Лучший ответ

Причиной сравнения является неправильная методика использования. Даже если вы получите сравнение "правильно", счетчик циклов с плавающей запятой будет накапливать ошибку с итерации на итерацию.

Вы можете устранить накопление ошибки, используя точную арифметику для счетчика циклов. Он может по-прежнему иметь тип с плавающей запятой, но вы используете точно представляемые значения, например:

for (double i = 12; i <= 13; ++i)

Затем, внутри цикла, вы масштабируете счетчик по желанию:

for (double i = 12; i <= 13; ++i)
{
    double x = i / 1000.;
     …
}

Очевидно, что в цикле с двумя итерациями не так много ошибок. Тем не менее, я ожидаю, что ваши значения - всего лишь один пример, и на практике могут быть более длинные циклы. С помощью этой технологии единственная ошибка в x заключается в операции масштабирования, поэтому на каждой итерации вместо одной на итерацию должна быть только одна ошибка.

Обратите внимание, что деление на 1000 точнее, чем масштабирование на.001. Разделение на 1000 имеет только одну ошибку (в разделе). Однако, поскольку.001 не является точно представимым в двоичной плавающей точке, умножение на него имеет две ошибки (при преобразовании.001 в плавающую точку и в умножении). С другой стороны, деление обычно происходит очень медленно, поэтому вы можете выбрать умножение.

Наконец, хотя этот метод гарантирует желаемое количество итераций, масштабированное значение может быть незначительным за пределами идеального целевого интервала в первой или последней итерации из-за ошибки округления при масштабировании. Если это имеет значение для вашего приложения, вы должны настроить значение в этих итерациях.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню