2013-10-06 3 views
0

У меня есть цикл в цикле число с плавающей в пределах между минимальным и максимальным диапазоном, как следоватьо флоат номер Comparision в C++

#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++?

+1

Нет, нет ничего встроенного. Толерантность точки плавающей запятой и обработка ошибок зависят от приложения. – Barmar

+7

Вместо итерации по значениям с плавающей запятой, итерации с целыми числами, а затем разделите их на 1000.0, чтобы получить дроби. – Barmar

+0

В поддержку комментария @ Barmar. Накопление с плавающей запятой может накапливать ошибку округления. EPS может потребоваться больше для большего количества итераций. Между тем, у вас есть мнение о том, сколько итераций вы хотите, в целочисленных терминах. –

ответ

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 в плавающую точку и в умножении). С другой стороны, деление обычно происходит очень медленно, поэтому вы можете выбрать умножение.

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

Смежные вопросы