Точность Matlab: простое вычитание не равно нулю - PullRequest
1 голос
/ 27 октября 2011

Я вычисляю эту простую сумму на Matlab:

2*0.04-0.5*0.4^2 = -1.387778780781446e-017

но результат не ноль. Что я могу сделать?

Ответы [ 5 ]

4 голосов
/ 27 октября 2011

Аабаз и Джим Клэй имеют хорошие объяснения того, что происходит.

Часто бывает, что вместо точного вычисления значения 2 * 0,04 - 0,5 * 0,4 ^ 2 вам действительно нужно проверить, отличаются ли 2 * 0,04 и 0,5 * 0,4 ^ 2 на небольшую величину достаточно, чтобы быть в пределах соответствующей числовой точности. Если это так, то вместо того, чтобы проверять 2*0.04 - 0.5*0.4^2 == 0, вы можете проверить, является ли abs(2*0.04 - 0.5*0.4^2) < thresh. Здесь thresh может быть произвольным небольшим числом или выражением, включающим eps, которое дает точность числового типа, с которым вы работаете.

EDIT: Спасибо Джиму и Талу за предложенное улучшение. Изменено для сравнения абсолютного значения разницы с порогом, а не с разницей.

2 голосов
/ 27 октября 2011

Matlab использует числа с плавающей запятой двойной точности для хранения действительных чисел. Это числа вида m*2^e, где m - целое число от 2^52 до 2^53 ( мантисса ) и e - показатель степени. Давайте назовем число числом с плавающей запятой, если оно имеет эту форму.

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

Итак, всякий раз, когда вы пишете что-то вроде 0.04 в Matlab, вы действительно говорите: «Получите мне число с плавающей точкой, которое ближе всего к 0.04. В вашем выражении есть 2 числа, которые должны быть аппроксимированы: 0.04 и 0.4.

Кроме того, точный результат таких операций, как сложение и умножение чисел с плавающей запятой, может не быть числом с плавающей запятой. Хотя оно всегда имеет форму m*2^e, мантисса может быть слишком большой. Таким образом, вы получаете дополнительную ошибку при округлении результатов операций.

В конце дня простое выражение, подобное вашему, будет отключено примерно в 2 ^ -52 раз больше операндов, или примерно в 10 ^ -17.

В итоге: причина, по которой ваше выражение не оценивается как ноль, является двойной:

  1. Некоторые цифры, с которых вы начинаете, отличаются (приблизительными) от точных цифр, которые вы указали.
  2. Промежуточные результаты также могут быть приблизительными точными результатами.
1 голос
/ 27 октября 2011

То, что вы видите, это ошибка квантования . Matlab использует двойные числа для представления чисел, и, хотя они способны с высокой точностью, они по-прежнему не могут представлять все действительные числа, потому что существует бесконечное число действительных чисел. Я не уверен в уловке Аабаза, но в целом я бы сказал, что вы ничего не можете сделать, кроме, возможно, массирования ваших входов, чтобы получить двойные числа.

1 голос
/ 27 октября 2011

Я почти уверен, что это случай старых ошибок с плавающей запятой.

Вам нужна точность 1e-17? Является ли это просто желанием получить «симпатичный» результат? В этом случае вы можете просто использовать отформатированный sprintf для отображения необходимого количества значащих цифр.

Поймите, что это не проблема Matlab, а фундаментальное ограничение представления чисел в двоичном виде.

Ради интереса, выясните, что .1 находится в двоичном виде ...

Некоторые ссылки: http://en.wikipedia.org/wiki/Floating_point#Accuracy_problems http://www.mathworks.com/support/tech-notes/1100/1108.html

1 голос
/ 27 октября 2011

Я не знаю, применимо ли это к вашей проблеме, но часто самым простым решением является масштабирование ваших данных.

Например:

a=0.04;
b=0.2;
a-0.2*b
ans=-6.9389e-018
c=a/min(abs([a b]));
d=b/min(abs([a b]));
c-0.2*d
ans=0

РЕДАКТИРОВАТЬ Конечно, я не хотел дать универсальное решение этих проблем, но это хорошая практика, которая может помочь вам избежать нескольких проблем в численных вычислениях (подбор кривой и т. д.).См. Ответ Джима Клея о причине, по которой вы испытываете эти проблемы.

...