Pull to refresh

Comments 22

Многие программисты об этом забывают по тому, что арифметика с плавающей точкой встречается на порядок реже, чем целочисленная. Да и ошибки здесь на порядок веселее. Вспомнился такой код:
double d = 0;
for(int i=0;i<1000;i++) d += 0.2;
bool eq = (d == 200);
если не видно разницы, зачем платить больше?
Дело в том, что такие ошибки допускают люди, которые по несколько лет почти ежедневно имеют дело с плавающей точкой. Вектора, матрицы, кватернионы каждый день, а потом раз и такая ошибка в коде. А им ведь деньги за этот код платят.
Большинство программистов даже зная как устроен дабл будут допускать подобные ошибки. И проблема совсем в другом — в понимании. А дабл нужно понимать как value + eps, где value то что вы хотели представить как double, а eps — относительная погрешность округления (машинное Эпсилон). Если взять пример автора и провести анализ относительных погрешностей:
r (x1) = r (y1) = r (x2) = r (y2) = eps,
r (x1 * x1 + y1 * y1) = r (x2 * x2 + y2 * y2) = 4 * eps,
r (len1) = r (len2) = 3 * eps,
r (x1 / len1) = r (y1 / len1) = r (x2 / len2) = r (y2 / len2) = 5 * eps,
r (dotProduct) = 12 * eps, если брать x1 * x2 и y1 * y2 одного знака как в примере автора.
Вот теперь понятно откуда берутся значения больше 1.0. Вы думаете каждый программист без соответствующего мат. образования может выполнить такой анализ?
Надо считать точнее: r(x1*x1+y1*y1)=2*x1*r(x1)+2*y1*r(y1)+(x1^2+y1^2+(x1^2+y1^2))*eps = 2*(x1+y1+x1^2+y1^2)*eps. В итоге результат может оказаться совершенно другим. Например при извлечении корня могут появляться члены вроде eps^{1/2}. А это уже вполне чувствительная величина.
Минуточку x1 * x1 и y1 * y1 строго больше нуля. Поетому r(x1 * x1 + y1 * y1) = min(r(x1*x1), r(y1*y1)) + eps = min(r(x1) + r(x1) + eps, r(y1) + r(y1) + eps) + eps = min(3*eps, 3*eps) + eps = 4*eps.
Поправка вместо min должен быть max, но суть таже.
Дело в том, что погрешность в x1 увеличивается сама по себе даже при точном возведении в квадрат — (x1+eps)*(x1+eps)=x1^2+2*x*eps+eps*eps. К этому мы добавляем погрешность произведения (она относительна в виду природы строения действительных чисел) — x1*x1*eps. Членами eps^2 пренебрегаем.
PS На самом деле r(x1)=0, и погрешность получается меньше — 2*(x1^2+y1^2)*eps.
Простите, но используйте тег без него сложно читать...
В таком случае я не понимаю чем мой ответ отличается от ваших рассуждений. Относительная ошибка
r(x1 * x1) у вас тоже 3 * eps.
Как вовремя статейка подвернулась! Я только что мучился с векторным 2d движком и как раз эта проблема была. Я топорно решил: умножал каждое число на 100 000, потом округлял, потом делил на 100 000. Ну тупо рубил количество знаков после запятой т.к. максимальная точность не нужна для этого игродвижка, как выяснилось.
Классика жанра, читать всем кто использует вычисления с плавающей точкой:
What Every Computer Scientist Should Know About Floating-Point Arithmetic
ЗЫ pdf гуглится
В первом примере надо сравнивать, делитель меньше FLT_MIN или нет? Прост смущает как что-то может быть меньше чем самое маленькое вещественное число.
FLT_MIN — это не самое маленькое вещественное число, это самое маленькое положительное денормализованное число, которое может хранить float.
На самом деле, самое маленькое число представимое в float. Которое обычно будет subnormal, но может и не быть, если платформа не поддерживает subnormal числа.
Да, таким вещам надо учить с младенчества!
image
Это же язык для извращенцев, в нормальном языке программирования не должно быть запутанностей и нелогичностей, и штука вроде if (b != 0) { result = a /b } должна работать для абсолютно любых значений переменных, потому что программистам больше делать наверно нечего, как читать многостраничные мануалы по IEEE сколько-то там.

Если бы Марк Цукенберг занимался такой ерундой, фейсбук бы не появился.
double и в Африке double. И если в вашем коде есть нечто вроде if (b! = 0) {result = a / b} это свидетельствует не о проблеме языка программирования, а о проблеме реализации.
Для b == 0, a / b == INF, что соответствует реальности, поэтому не вижу никаких неточностей со стороны языка программирования. Что вы называете тогда нормальным языком программирования?
UFO just landed and posted this here
UFO just landed and posted this here
Sign up to leave a comment.

Articles