Просто день открытий какой-то!

Oct 03, 2017 23:20

1) + на float не ассоциативный.

2) Если приложение которое насилует БД ускорить по CPU в 2 раза, то БД будет насиловаться в 2 раза интенсивнее!

Leave a comment

kodt_rsdn October 3 2017, 22:08:47 UTC
Ассоциативный, но в пределах погрешности. А если погрешность опережает значащую часть, то, конечно, извините! А если настаивать на том, что значащие разряды там все до последнего бита (например, для побитового сравнения) - то два раза извините.

Собственно, коммутативность и ассоциативность сложения используется в борьбе против ошибок, особенно - ошибок нормализации и денормализации.
Потому что мы-то знаем, что от перестановки _искомая_ сумма не меняется.

Reply

kunaifusu October 4 2017, 05:10:29 UTC
Смотря что называть "погрешностью". E.g.
abs (a0 + a1 + ... + an+x) - (x + a0 + a1 + ... + an) для x=2^24 и 0 < ai < 1 может быть 2^24-1, что явно больше погрешности представления любого слагаемого. Для практических применений он совершенно не ассоциативный.

Reply

kodt_rsdn October 4 2017, 08:40:34 UTC
Для практических применений (физматмоделирование, бухгалтерия) всегда считают погрешность вычислений.

Если у нас одно из слагаемых имеет порядок 1e24, это значит, что ошибка денормализации может достигать 1e0 для каждого сложения, итого может набежать n+2.

Тогда, как честные люди, мы напишем abs((a0+...+an+x)-(x+a0+...+an)) <= eps - что является типичной формулой приближённого сравнения вещественных чисел. Наши суммы приближённо равны, ЧТД (ИЧСХ).
Ну да, eps тут здоровенный. Однако, abs(eps/x) <= FLT_EPSILON*(n+2), что не так уж и плохо, э?

Reply

kunaifusu October 4 2017, 14:29:42 UTC
С такими аргументами любой оператор ассоциативный. abs(x/(y/z)) - (x/y)/z) < eps, где eps - здоровенный.

Reply

kodt_rsdn October 4 2017, 18:18:06 UTC
Нет, потому что деление не ассоциативно по определению.

Reply

kunaifusu October 4 2017, 18:23:32 UTC
И я о том же, в определении ассоциативности нет никаких "пределов погрешности".

Reply

kodt_rsdn October 5 2017, 10:36:03 UTC
Вот нифига.
Для подмножества-с-операциями (что это? абелева группа, если речь идёт только о +, или будем дотягивать до алгебры?) представимых float'ов ассоциативность выполняется безо всяких оговорок на погрешность.

0.1 само по себе непредставимо
1e25 + 1 - результат непредставим

А для 1+2+3 всё прекрасно.
А если мы вместо дебильного побитового сравнения == будем использовать сравнение с вычисленной погрешностью (а все умные математики и бухгалтеры именно это и делают), то операбельное подмножество флотов окажется гораздо шире.

Это не + неассоциативен, а == некорректно. Вот в чём дело.

А с делением такое в принципе не прокатит. Поэтому давайте не разводите демагогию.

Reply

kkirsanov October 4 2017, 05:39:06 UTC
Я в этом смысле:

In [1]: (0.1+0.2)+0.3==0.1+(0.2+0.3)
Out[1]: False

Ну и на больших суммах конечно разъезжается еще дальше.

Reply

kodt_rsdn October 4 2017, 08:29:42 UTC
Это и есть: опрометчиво считать все разряды значащими (что делает операция ==).

Даже если бы здесь не было ошибки денормализации (а она есть, поскольку 0.1=0.xxx*2^-4, 0.2=0.xxx*2^-3, 0.3=0.yyy*2^-2), - всё равно, непредставимые двоичные дроби, там самый младший разряд мантиссы содержит ошибку округления. А после двух сложений - ошибку округления содержат уже 2, если не 3 младших разряда.

Можно относиться к этому, как к шуму.
Без шумоподавления 0.6±eps != 0.6±eps, даже если мы просто два раза напишем 0.6 и пропустим через шумящий канал.

Просто для фиксированной (или денормализованной) арифметики ошибка набегает линейно, по количеству членов суммы. А для плавающей денормализация может выстрелить сразу на все деньги.
(-1e100 + 1e100) + 100500 = 0+100500 = 100500
(-1e100) + (1e100 + 100500) = -1e100 + 1e100 = 0
Но, в масштабах 1e45 (это младший разряд числа 1e100), оба результата практически равны!

Reply


Leave a comment

Up