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

Я использую 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;
}

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

1

Решение

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

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

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

Другие решения

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

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

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

Чтобы проиллюстрировать это, возьмите 1.000, делите на 3, а затем умножьте на 3, вы должны вернуться к 1.000, но, поскольку 1.000 / 3 = от 0.333 до 3 десятичных знаков, не удивляйтесь, если результат будет 0.999. (Компьютеры используют бинарный файл (база 2), так что это может сработать иначе, но точка зрения остается неизменной)

3

По вопросам рекламы [email protected]