Comments 22
Многие программисты об этом забывают по тому, что арифметика с плавающей точкой встречается на порядок реже, чем целочисленная. Да и ошибки здесь на порядок веселее. Вспомнился такой код:
double d = 0;
for(int i=0;i<1000;i++) d += 0.2;
bool eq = (d == 200);
-5
Упс, ошибся, там d+=0,1 и d==100
0
Дело в том, что такие ошибки допускают люди, которые по несколько лет почти ежедневно имеют дело с плавающей точкой. Вектора, матрицы, кватернионы каждый день, а потом раз и такая ошибка в коде. А им ведь деньги за этот код платят.
+2
Большинство программистов даже зная как устроен дабл будут допускать подобные ошибки. И проблема совсем в другом — в понимании. А дабл нужно понимать как 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) = 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. Вы думаете каждый программист без соответствующего мат. образования может выполнить такой анализ?
+4
Надо считать точнее: 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}. А это уже вполне чувствительная величина.
+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.
0
Поправка вместо min должен быть max, но суть таже.
0
Дело в том, что погрешность в 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.
PS На самом деле r(x1)=0, и погрешность получается меньше — 2*(x1^2+y1^2)*eps.
0
Простите, но используйте тег
без него сложно читать...
+1
В таком случае я не понимаю чем мой ответ отличается от ваших рассуждений. Относительная ошибка
r(x1 * x1) у вас тоже 3 * eps.
r(x1 * x1) у вас тоже 3 * eps.
0
Как вовремя статейка подвернулась! Я только что мучился с векторным 2d движком и как раз эта проблема была. Я топорно решил: умножал каждое число на 100 000, потом округлял, потом делил на 100 000. Ну тупо рубил количество знаков после запятой т.к. максимальная точность не нужна для этого игродвижка, как выяснилось.
+1
Классика жанра, читать всем кто использует вычисления с плавающей точкой:
What Every Computer Scientist Should Know About Floating-Point Arithmetic
ЗЫ pdf гуглится
What Every Computer Scientist Should Know About Floating-Point Arithmetic
ЗЫ pdf гуглится
+2
В первом примере надо сравнивать, делитель меньше FLT_MIN или нет? Прост смущает как что-то может быть меньше чем самое маленькое вещественное число.
0
FLT_MIN — это не самое маленькое вещественное число, это самое маленькое положительное денормализованное число, которое может хранить float.
+1
Да, таким вещам надо учить с младенчества!
+2
Это же язык для извращенцев, в нормальном языке программирования не должно быть запутанностей и нелогичностей, и штука вроде if (b != 0) { result = a /b } должна работать для абсолютно любых значений переменных, потому что программистам больше делать наверно нечего, как читать многостраничные мануалы по IEEE сколько-то там.
Если бы Марк Цукенберг занимался такой ерундой, фейсбук бы не появился.
Если бы Марк Цукенберг занимался такой ерундой, фейсбук бы не появился.
-7
double и в Африке double. И если в вашем коде есть нечто вроде if (b! = 0) {result = a / b} это свидетельствует не о проблеме языка программирования, а о проблеме реализации.
Для b == 0, a / b == INF, что соответствует реальности, поэтому не вижу никаких неточностей со стороны языка программирования. Что вы называете тогда нормальным языком программирования?
Для b == 0, a / b == INF, что соответствует реальности, поэтому не вижу никаких неточностей со стороны языка программирования. Что вы называете тогда нормальным языком программирования?
+2
Толсто, очень толсто.
+2
UFO just landed and posted this here
UFO just landed and posted this here
Sign up to leave a comment.
Откуда берутся NaNы?