Странная математическая ошибка при сравнении двух двойных значений в NS-3 C++

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

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

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

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

i.e

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;
}

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


person GreenGodot    schedule 14.02.2014    source источник
comment
docs.oracle.com/cd/E19957-01/806- 3568/ncg_goldberg.html   -  person knivil    schedule 14.02.2014


Ответы (2)


Формат с плавающей запятой использует двоичное представление мантиссы и экспоненты, он не может точно выразить каждую десятичную (десятичную) числовую дробь, и его точность ограничена, поэтому обязательно проверьте, может ли двойной формат точно представлять ваши значения. Подробнее о двойном формате здесь, в Википедии. Есть еще вопросы о точности с плавающей запятой при переполнении стека, проверьте windows-and-linux-why">этот и другие, связанные с ним.

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

  1. вы не можете рассчитывать на то, что получите точное значение желаемых чисел
  2. вы не можете просто сравнивать числа на равенство, (1.0+2.0)==3.0 может работать, но более сложные вычисления с дробями не могут сравнивать равные...
  3. точность числа с плавающей запятой ограничена, когда вы суммируете или умножаете много чисел вместе, особенно с разными показателями степени, вы накапливаете большую ошибку в вычислениях (см. алгоритм суммирования Каана)
person nio    schedule 14.02.2014

Действительные числа простираются от + бесконечности до - бесконечности с бесконечно малыми промежутками между числами. Невозможно представить все действительные числа в конечной памяти.

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

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

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

person doron    schedule 14.02.2014