Причина
Плавающая точка не может хранить все десятичные значения точно.Поэтому при использовании форматов с плавающей запятой всегда будут ошибки округления входных значений.Ошибки на входах курса приводят к ошибкам на выходе.В случае дискретной функции или оператора на выходе может быть большая разница вокруг точки, где функция или оператор дискретны.Оператор по модулю дискретен, и ваш случай является ярким примером этой проблемы.
Ввод и вывод для значений с плавающей запятой
Итак, при использовании переменных с плавающей запятой вывсегда должен знать об этом.И любой вывод, который вы хотите получить из вычисления с плавающей запятой, всегда должен быть отформатирован / обработан перед отображением с учетом этого.
Когда используются только непрерывные функции и операторы, часто выполняется округление до желаемой точности (не обрезать),Стандартные функции форматирования, используемые для преобразования чисел с плавающей запятой, обычно делают это для вас.
Чтобы иметь правильный вывод, основанный на ожидаемой точности ввода и желаемой точности вывода, вы также должны
- Округлые вводыс ожидаемой точностью или убедитесь, что никакие значения не могут быть введены с более высокой точностью.
- Перед округлением / форматированием добавьте небольшое значение к выводам, которое меньше или равно 1/4 от требуемой точности и большечем максимальная ожидаемая ошибка, вызванная ошибками округления на входе и во время расчета.Если это невозможно, комбинации точности используемого типа данных недостаточно, чтобы обеспечить желаемую точность вывода для ваших расчетов.
Эти две вещи часто не выполняются, и в большинстве случаев различия, вызванные их отсутствием, слишком малы, чтобы быть важными для большинства пользователей, но у меня уже был проект, в котором вывод не был принятпользователи без этих исправлений.
Дискретные функции или операторы (например, по модулю)
Когда задействованы дискретные операторы или функции, могут потребоваться дополнительные исправления, чтобы обеспечить выводкак и ожидалось.Округление и добавление небольших поправок перед округлением не может решить проблему.
Может потребоваться специальная проверка / исправление промежуточных результатов вычислений сразу после применения дискретной функции или оператора.
Особый случайэтого вопроса
В этом случае вы ожидаете ввод с определенной точностью, поэтому можно скорректировать вывод для воздействия ошибок округления, которые намного меньше, чем требуемая точность.
Если мы говорим, что точность вашего типа данных равна e.
Ваш ввод будет сохранен не как введенные вами значения a и b, а как * (1 +/- e) и b * (1 + /).-e)
Результат деления a * (1 +/- e) на b * (1 +/- e) приведет к (a / b) (1 +/- 2e).
Функция по модулю должна обрезать результат и снова умножить.Таким образом, результат будет (a / b b) (1 +/- 3e) = a (1 +/- 3e), что приведет к ошибке * 3e.
Мод добавляет * e квозможная ошибка a * 3e из-за вычитания 2 значений с возможными ошибками a * 3e и a * e.
Таким образом, вы должны убедиться, что общая возможная ошибка a * 4e меньше требуемой точности, и еслиусловие выполнено, и результат отличается не более чем от b от максимально возможной ошибки, вы можете смело заменить ее на 0.
Лучше избежать возникновения проблемы
часто более эффективно избежать этих проблем, используя типы данных (целочисленные или с фиксированной запятой) для таких вычислений, которые могут хранить ожидаемый ввод без ошибок округления.Примером этого является то, что вы никогда не должны использовать значения с плавающей запятой для финансовых расчетов.