Как выбрать значение epsilon для плавающей точки? [закрытый]
Поскольку мы знаем, что 0.1 + 0.2 != 0.3
из-за ограниченного представления чисел, нам нужно вместо этого проверить шляпу abs(0.1+0.2 - 0.3) < ε
. Вопрос в том, какое значение ε мы обычно выбираем для различных типов? Можно ли оценить его в зависимости от количества битов и количества и типов операций, которые, вероятно, будут выполнены?
3 ответа:
Вы оцениваете машину Эпсилон, используя алгоритм ниже. Вам нужно умножить этот Эпсилон на целое число 1+(log (number)/log(2)). После того как вы определили это значение для всех чисел в вашем уравнении, вы можете использовать анализ ошибок для оценки значения Эпсилона для конкретного вычисления.
epsilon=1.0 while (1.0 + (epsilon/2.0) > 1.0) { epsilon = epsilon /2.0 } //Calculate error using error analysis for a + b epsilon_equation=Math.sqrt(2*epsilon*epsilon) document.write('Epsilon: ' + epsilon_equation+'<br>') document.write('Floating point error: ' + Math.abs(0.2 + 0.4 -0.6)+'<br>') document.write('Comparison using epsilon: ') document.write(Math.abs(0.2 + 0.4 -0.6)<epsilon_equation)
Следуя вашему замечанию, я попробовал тот же подход в C# , и он, кажется, работает:
using System; namespace ConsoleApplication { public class Program { public static void Main(string[] args) { double epsilon = 1.0; while (1.0 + (epsilon/2.0) > 1.0) { epsilon = epsilon/2.0; } double epsilon_equation = Math.Sqrt(2*epsilon*epsilon); Console.WriteLine(Math.Abs(1.0 + 2.0 - 3.0) < Math.Sqrt(3.0 * epsilon_equation * epsilon_equation)); } } }
Базовое значение для Эпсилона-это разница между
Обратите внимание, что, как минимум, вам нужно масштабировать это значение в пропорции к фактическому числу, которое вы тестируете. Кроме того, поскольку точность масштабируется только приблизительно с числовым значением, вы можете увеличить свою маржу на небольшой коэффициент, чтобы предотвратить ложные ошибки:1.0
и следующим по величине репрезентативным значением. В C++ это значение доступно какstd::numeric_limits<T>::epsilon()
.double epsilon = std::numeric_limits<double>::epsilon(); // C++ literals and math functions are double by default bool is_near = abs(0.1+0.2 - 0.3) <= 0.3 * (2*epsilon);
Как более полный пример, функция для сравнения дубли:
На практике фактическое значение Эпсилона, которое вы должны использовать, зависит от того, что вы делаете и какой тип допуска вам действительно нужен. Числовые алгоритмы обычно имеют допуски точности (среднее и максимальное), а также оценки времени и пространства. Но оценка точности обычно начинается с чего-то вродеbool is_approximately_equal(double a, double b) { double scale = max(abs(a), abs(b)); return abs(a - b) <= scale * (2*epsilon); }
characteristic_value * epsilon
.
Мне известен следующий подход к точному вычислению предикатов с плавающей запятой: вычислите значение, используя стандартные типы с плавающей запятой, и вычислите ошибку. Обычно предикат может быть задан как
p(x) == 0
илиp(x) < 0
и т. д. Если абсолютное значениеp(x)
больше ошибки, то вычисления считаются точными. В противном случае используется интервальная или точная рациональная арифметика.Можно оценить ошибку по используемому выражению. Я слышал об автомате генераторы этого, но не смогли найти никаких ссылок.
Насколько мне известно, точные вычисления в основном используются для геометрии, и поиск в Google для "точных геометрических вычислений" дает много информации по этой теме.Вот статья , которая каким-то образом объясняет оценку ошибок.