2014-02-14 1 views
1

Я использую NS-3 (написанный на C++) для имитации сетевой среды.Странная математическая ошибка при сравнении двух двойных значений в NS-3 C++

Я использую класс flowmonitor для записи показателей производительности из беспроводной линии.

Единственное, что я собираю, это временная дисперсия между текущей и предыдущей задержкой пакета или «джиттером».

Чтобы получить это, я вычитаю значение времени (преобразованное в двойную переменную) одной задержки пакета в предыдущее значение.

т.е.

0,0159051 - 0,0158002 = 0,0001049

Однако, через некоторое время математика, кажется, действует очень странно, такие как:

0.0159003 - 0.0158007 = 9.95972e-05

когда это ответ должен быть явно 0,0000996

Чтобы подробнее остановиться, я первоначально использовал функцию diff, чтобы найти разницу.

template <typename T1, typename T2> 
double diff(const T1& lhs, const T2& rhs) 
{ 
    std::cout << lhs << " - " << rhs << std::endl; 
    return lhs - rhs; 
} 

Но так как я обнаружил ошибку, я попробовал прямое вычитание, но получаю ту же ошибку.

+2

http://docs.oracle.com/cd/E19957-01/806-3568/ncg_goldberg.html – knivil

ответ

6

Формат с плавающей запятой использует двоичное представление мантиссы и экспоненты, он не может точно выразить каждую десятичную (десятичную) числовую долю, и ее точность ограничена, поэтому обязательно проверьте, может ли двойной формат точно представлять ваши значения , Подробнее о двойном формате here on wikipedia. Существует больше вопросов о точности с плавающей точкой при переполнении стека, проверьте this one и другие связанные с ним.

Есть некоторые последствия:

  1. вы не можете рассчитывать на что вы получите точное значение ваших желаемых чисел
  2. вы не можете просто сравнить цифры равенства, (1.0+2.0)==3.0 могли бы работать, но более сложный расчет с дробями не мог сравниться ...
  3. Точность числа с плавающей запятой ограничена, когда вы суммируете или умножаете много чисел вместе, особенно с разными показателями, вы будете аккумулировать большую ошибку при вычислении (см. Kahan summation algorithm)
3

Реальные числа простираются от + бесконечности до бесконечности с бесконечно малыми промежутками между числами. Это невозможно представить все реальные числа в конечном хранилище.

Чтобы обойти эту проблему, компьютер хранит величину числа (как показатель степени) и число значимых цифр (мантисса). Это похоже на запись числа 1.043 X 10^-5.

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

Чтобы проиллюстрировать точку, возьмите 1.000 разделить на 3, а затем умножьте на 3, вы должны вернуться к 1.000, но с 1.000/3 = 0.От 333 до 3 знаков после запятой, не удивляйтесь, если результат равен 0.999. (Компьютеры используют двоичный код (base 2), так что это может получиться по-другому, но точка все еще стоит)

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