Если вы ищете надежную границу для ошибки округления, вам не обязательно нужна библиотека с точностью до aribtrary. Вместо этого вы можете использовать анализ ошибок.
Мне не удалось найти хорошую онлайн-справку, но все это описано в разделе 3.3 книги Ника Хайама «Точность и стабильность численных алгоритмов». Идея довольно проста:
- Перефакторинг вашего кода, чтобы у вас было одно назначение одной арифметической операции в каждой строке.
- Например, для каждой переменной
xсоздайте переменную, x_errкоторая инициализируется нулем, когда ей xприсваивается константа.
- Например, для каждой операции
z = x * yобновите переменную, z_errиспользуя стандартную модель арифметики с плавающей запятой, а также возникающие zи текущие ошибки x_errи y_err.
- Возвращаемое значение вашей функции должно также иметь соответствующее
_errзначение. Это зависит от данных на вашей общей ошибки округления.
Сложная часть - шаг 3. Для самых простых арифметических операций вы можете использовать следующие правила:
z = x + y -> z_err = u*abs(z) + x_err + y_err
z = x - y -> z_err = u*abs(z) + x_err + y_err
z = x * y -> z_err = u*abs(z) + x_err*abs(y) + y_err*abs(x)
z = x / y -> z_err = u*abs(z) + (x_err*abs(y) + y_err*abs(x))/y^2
z = sqrt(x) -> z_err = u*abs(z) + x_err/(2*abs(z))
где u = eps/2блок округления. Да, правила для +и -одинаковы. Правила для любой другой операции op(x)могут быть легко извлечены с использованием разложения в ряд Тейлора для примененного результата op(x + x_err). Или вы можете попробовать поискать в Google. Или используя книгу Ника Хайама.
В качестве примера рассмотрим следующий код Matlab / Octave, который оценивает полиномы в коэффициентах aв точке, xиспользуя схему Хорнера:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
s = a(k) + x*s;
end
Для первого шага мы разделили две операции на s = a(k) + x*s:
function s = horner ( a , x )
s = a(end);
for k=length(a)-1:-1:1
z = x*s;
s = a(k) + z;
end
Затем мы вводим _errпеременные. Обратите внимание, что входные данные aи xпредполагаются точными, но мы также можем также потребовать от пользователя передать соответствующие значения для a_errи x_err:
function [ s , s_err ] = horner ( a , x )
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = ...;
s = a(k) + z;
s_err = ...;
end
Наконец, мы применяем правила, описанные выше, чтобы получить условия ошибки:
function [ s , s_err ] = horner ( a , x )
u = eps/2;
s = a(end);
s_err = 0;
for k=length(a)-1:-1:1
z = x*s;
z_err = u*abs(z) + s_err*abs(x);
s = a(k) + z;
s_err = u*abs(s) + z_err;
end
Обратите внимание, что поскольку у нас нет a_errили x_err, например, они предполагаются равными нулю, соответствующие выражения просто игнорируются в выражениях ошибок.
И вуаля! Теперь у нас есть схема Хорнера, которая возвращает оценку ошибки в зависимости от данных (примечание: это верхняя граница ошибки) вместе с результатом.
В качестве примечания, поскольку вы используете C ++, вы можете рассмотреть возможность создания собственного класса для значений с плавающей запятой, который переносит _errтермин и перегружает все арифметические операции для обновления этих значений, как описано выше. Для больших кодов это может быть более простой, хотя и менее эффективный в вычислительном отношении маршрут. Сказав это, вы можете найти такой класс в Интернете. Быстрый поиск в Google дал мне эту ссылку .
PS Обратите внимание, что все это работает только на машинах, строго придерживающихся IEEE-754, то есть все арифметические операции с точностью до . Этот анализ также дает более жесткую, более реалистичную границу, чем использование интервальной арифметики, поскольку по определению вы не можете представлять число в плавающей точке, т.е. ваш интервал будет просто округляться до самого числа.x ( 1 ± u )± тых ( 1 ± у )