Как мне сделать сравнение с плавающей запятой? - PullRequest
72 голосов
/ 06 февраля 2011

Я сейчас пишу некоторый код, где у меня есть что-то вроде:

double a = SomeCalculation1();
double b = SomeCalculation2();

if (a < b)
    DoSomething2();
else if (a > b)
    DoSomething3();

А затем в других местах мне может потребоваться сделать равенство:

double a = SomeCalculation3();
double b = SomeCalculation4();

if (a == 0.0)
   DoSomethingUseful(1 / a);
if (b == 0.0)
   return 0; // or something else here

ВКороче говоря, у меня много математики с плавающей запятой, и мне нужно делать различные сравнения условий.Я не могу преобразовать это в целочисленную математику, потому что такая вещь не имеет смысла в этом контексте.

Я читал ранее, что сравнения с плавающей запятой могут быть ненадежными, так как у вас могут быть такие вещи:*

double a = 1.0 / 3.0;
double b = a + a + a;
if ((3 * a) != b)
    Console.WriteLine("Oh no!");

Короче говоря, я хотел бы знать: как я могу надежно сравнивать числа с плавающей запятой (меньше, больше, чем равенство)?

Диапазон чиселЯ использую примерно от 10E-14 до 10E6, поэтому мне нужно работать как с маленькими, так и с большими числами.

Я отметил это как независимость от языка, потому что мне интересно, как я могу достичьэто неважно на каком языке я использую.

Ответы [ 11 ]

0 голосов
/ 06 февраля 2011

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

#define EPSILON 0.00000001

if ((a - b) < EPSILON && (b - a) < EPSILON) {
  printf("a and b are about equal\n");
}

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

...