О плавающей точке
lexa - 14/Мар/2011 18:09
Что напечатает:
unsigned short v=59259;
float a=0.0f;
double b=0.0;
for(int i=0;i<33*33;i++)
{
a+=v;
b+=v;
}
printf("%g\n",(a-b)/(33*33));
float a=0.0f;
double b=0.0;
for(int i=0;i<33*33;i++)
{
a+=v;
b+=v;
}
printf("%g\n",(a-b)/(33*33));
Вроде и значения все вполне небольшие, и число итераций сложения вполне человеческое, однако ж.
P.S. При особом везении тут можно и третий знак разницы получить, а не шестой....
Comments
unsigned short v=59259; float a=0.0f; double b=0.0;
unsigned short v=59259;
float a=0.0f;
double b=0.0;
char ahtung=' ';
for(int i=0;i<33*33;i++)
{
a+=v;
b+=v;
if (a!=b) ahtung='!';
cout << i << " " << a << " " << b << " " << ahtung << "\n";
}
cout << (a-b)/(33*33) << "a = " << a << "b = "<< b;
char r;
cin >> r;
return 0;
}
282 1.67703e+007 1.67703e+007
283 1.68296e+007 1.68296e+007
284 1.68888e+007 1.68888e+007 !
285 1.69481e+007 1.69481e+007 !
286 1.70073e+007 1.70073e+007 !
287 1.70666e+007 1.70666e+007 !
А можно объяснить для поручиков, зачем перемножать 33*33, если компилятор это соптимизирует?
Ну потому что мне лень было умножать в уме, а это реальная к
Ну потому что мне лень было умножать в уме, а это реальная константа из реальной программы :)
У меня по плашке считается минимум-максимум (в целых), среднее (в плавучке) и стандартное отклонение (в плавучке же). При этом, отклонение считается правильно, в один проход (а не расчетом среднего и вычитанием вторым проходом).
Результат феноменальный:
минимум - 59259
максимум - 59259
дисперсия - 0
среднее - 59259.7
unsigned short v=59259; float a=0.0f; double b=0.0;
unsigned short v=59259;
float a=0.0f;
double b=0.0;
float averfa=0.0f;
double averdb=0.0;
char ahtung=' ';
for(int i=0;i<1089;i++)
{
if(i){ averfa=(v+averfa)/2.0;} else {averfa+=v;}
if(i){ averdb=(v+averdb)/2.0;} else {averdb+=v;}
a+=v;
b+=v;
if (a!=b) ahtung='!';
cout << i << " " << a << " " << b << " " << ahtung << " " << averfa << " " << averdb << "\n";
}
1087 6.44746e+007 6.44738e+007 ! 59259 59259
1088 6.45339e+007 6.45331e+007 ! 59259 59259
0.73921a = 6.45339e+007b = 6.45331e+007
Хмм? В один проход?
Неаккуратненько. if(i){ averfa=(v+averfa)/2.0f;} else {averf
Неаккуратненько.
if(i){ averfa=(v+averfa)/2.0f;} else {averfa+=v;}
Сорри.
Я не понимаю вашего кода. Вот смотрите: float avg=0.0f;
Я не понимаю вашего кода. Вот смотрите:
float avg=0.0f;
int i;
for(i=0;i<1000;i++)
{
float a = i;
if(i) { avg = (avg+a)/2.0f; } else { avg+=ф;}
}
printf("%g\n",avg);
Это же то же самое делает?
Но оно не среднее печатает, отнюдь.
ф читать как a :)
ф читать как a
:)
Да, лажаю. :-(
Да, лажаю. :-(
Блин, второй час ночи. Единственное, что удалось сделать, э
Блин, второй час ночи.
Единственное, что удалось сделать, это из 7 десятых 2 десятых на 1000 сложений. На 20000 разница жуткая.
Расскажите, как выйдете из ситуации, если будет свободное время, пожалуйста.
Да просто перешел на double - и все.
Да просто перешел на double - и все.
Все чаще убеждаюсь, что все
Все чаще убеждаюсь, что все уже придумано до нас. :-)
main ()
{
unsigned short v=59259;
float a=0.0f;
double b=0.0;
// float divider=100000.0;
// float divider=50000.0f;
float divider=1.0;
int i;
float c = 0.0f; //A running compensation for lost low-order bits.
float t;
float y;
float sum = 0.0f;
for(i=0;i<33*33;i++)
{
a+=v/divider;
b+=v/divider;
}
a*=divider;
b*=divider;
printf("%.15g a=%.15g b=%.15g a-b=%.15g int=%d iter=%d\n",(a-b)/(33*33), a, b, a-b, v*33*33, 33*33 );
// Vsjo pridumano do nas
a=0.0f;
b=0.0;
for(i=0;i<33*33;i++)
{
// a+=v; // see below
y = v - c; //So far, so good: c is zero.
t = sum + y; //Alas, sum is big, y small, so low-order digits of y are lost.
c = (t - sum) - y; //(t - sum) recovers the high-order part of y; subtracting y recovers -(low part of y)
sum = t; //Algebraically, c should always be zero. Beware eagerly optimising compilers!
//Next time around, the lost low part will be added to y in a fresh attempt.
b+=v;
}
a = sum;
printf("%.15g a=%.15g b=%.15g a-b=%.15g int=%d iter=%d\n",(a-b)/(33*33), a, b, a-b, v*33*33, 33*33 );
}
0.73921028466483 a=64533856 b=64533051 a-b=805 int=64533051 iter=1089
0.000918273645546373 a=64533052 b=64533051 a-b=1 int=64533051 iter=1089
Правда операций чуть побольше.
В вариации float/double (у
В вариации float/double (у обоих есть аппаратная поддержка) - это бессмысленно.
в с мы не можем спасти больше битов, чем их есть в мантиссе. Т.е. просто переход на double в аккумуляторе - делает не хуже, а операций - вчетверо меньше. Т.е. double-решение будет вдвое быстрее.
Но если не хватает double, то да, спасет.
Скока той мантиссы? Если мне
Скока той мантиссы? Если мне не изменяет память 24 бита. А скока их в а? 26? И ошибка в единичку (можно и в ноль свести при последующих вычислениях). Шайтан однако. :-)
Кстати gcc -O отличное от ноль тоже интересно.
Но в общем все правильно.
Ну да, мантиссы - 24 бита (не
Ну да, мантиссы - 24 бита (не помню, включает это знак или нет, но скорее всего 23 бита и знак). Это в float.
А в double - битов 48 или около того.
Но в float - 4 действия, а в double - одно, при этом double всего-то вдвое медленнее.
0.73921
замечательно ;)
Re: 0.73921
Ага.
И никаких тебе "вычитаний близких чисел", делений и тому подобного, на чем обычно ошибки накапливаются. Не говоря про переполнение.
Просто "случайное совпадение", в том смысле, что мы маленькое (в 7-8-м знаке) отклонение взяли и просуммировали 1089 раз.
Re: 0.73921
и double - не панацея (хотя конечно с double практически нереально наткнуться на что-то подобное)
Re: 0.73921
С даблом то же самое (по смыслу), только для получения эффекта того же порядка нужно не 1000 итераций в цикле, а 10^10.
А я тут давеча слышал вопль
А я тут давеча слышал вопль души по направлению к Интел и АМД "ну когда же в процессорах будет поддержка четверной точности". Не хватает кое-кому уже double.
У нас на факультете геофизики
У нас на факультете геофизики очень любили (и, возможно, до сих пор любят) Sun-ы за 128-битный float.
Re: 0.73921
И, кстати, кайф в том, что классический расчет стандартного отклонения (сначала среднее, потом дельты возводим в квадрат и суммируем) - даст неверный результат.
Кстати, к вопросу о float. Начал изучать libraw, так он всё-
Кстати, к вопросу о float. Начал изучать libraw, так он всё-таки не на float работает, да? То есть, в коде явно
ushort (*image)[4] ;
Основной объем работы - в целых. Что-то там внутрях - в плав
Основной объем работы - в целых. Что-то там внутрях - в плавучке.
Но постпроцессинг LibRaw - не перестаю это повторять - он не настоящий, это муляж такой, чтобы было.
В смысле, не настоящий? А, то есть основная идея, что постп
В смысле, не настоящий?
А, то есть основная идея, что постпроцессинг должен делать уже человек в своём приложении?
Да, целеполагание у LibRaw - это снять у прикладного програм
Да, целеполагание у LibRaw - это снять у прикладного программиста головную боль про 100 форматов и 400 камер.
То есть и постпроцессинг и даже вычитание черного - сам, все сам.
К несчастью, даже при таком уровне абстракции это трудно, обязательно всплывут обстоятельства (вроде Fuji с кривым aspect ratio и двумя кадрами), но всяко легче, чем без LibRaw.
Иначе нет смысла, чем один raw-процессор будет отличаться от другого, цветом рамочки вокруг light table?
Я думал, что libraw, в перспективе, и претендует стать самос
Я думал, что libraw, в перспективе, и претендует стать самостоятельным raw процессором. В принципе, оно уже сейчас им является, использовать вполне можно.
Просто как. Какие-то проблемы более эффективно решать на этапе до демозаики. Например, тот же debanding. Или, например, кто-то промеряет линейность ЦАП, и выдаст кривую. Какие-то - ещё до применения цветового профиля. Например - восстановление highlight clipping, или виньетки.
Какие-то, может, вообще по-хорошему нужно интегрировать в процесс демозаики. Например, подавление хроматических аберраций. Сейчас, да, это из области фантастики, да. Но в будущем у человечества, может, и до этого руки дойдут :-)
А если алгоритм шумоподавления захочет снять статданные, например, со служебной рамки изображения? Или кто-то захочет написать свою, расово правильную, систему цветокоррекции?
Ну, не говоря уже о том, что да. Появляются всякие fujy CCD, foveon, и другие. И, в конечном итоге, для них нужен вообще свой тип постпроцессинга.
Короче, я почему-то видел это как некую основу, уже куда можно интегрировать свои модули. Причём на всех этапах. А при желании, порядок этапов тоже менять.
<i>Я думал, что libraw, в перспективе, и претендует стать са
Я думал, что libraw, в перспективе, и претендует стать самостоятельным raw процессором.
Нет-нет. Эту тему мы обсуждали в самом начале и решили что нет, не претендуем. RAW-процессор *как библиотека* (т.е. приделывай свой GUI и радуйся) это какая-то неправильная штука. Или она будет слишком generic (и потому - медленной), либо там нужна какая-то строгая идеология процессинга, а тогда и GUI можно приделать свой (и исходники открывать необязательно).
Нет, этот самый постпроцессинг достался на халяву из dcraw, немножко разросся в последние полгода, но сильно развивать это место (на сегодняшний день) не планируется.
Иманна-иманна... Вот <a href='http://www.eecg.toronto.edu/~
Иманна-иманна...
Вот тут или на худой конец тут как гриццо совершенно famous article на этот счёт
Теорию я, типа, знаю. Но практика смешная: исходное 16-бит
Теорию я, типа, знаю.
Но практика смешная: исходное 16-битное число в 23-битную мантиссу лезет точно (во всяком случае, обратно печатается как надо, побитовое представление я не проверял). Итераций ~2^10 т.е. должно накопиться бита три ошибки. А накапливается - битов шесть.
Раскладец.
Хех, люблю я хитрые задачки) Делаем вот что: <pre> float v
Хех, люблю я хитрые задачки)
Делаем вот что:
float v = ((unsigned short)59259);
printf("v=%0.023f\n",v);
float a=0.0f;
double b=0.0;
bool bl=false;
for(int i=0;i<33*33;i++){
a+=v;
b+=v;
if (283==i) printf("a=%0.023f, b=%0.023f, i=%d\n",a,b,i);
if (a!=b && !bl){
bl=true;
printf("a=%0.023f, b=%0.023f, i=%d\n",a,b,i);
}
}
printf("%g\n",(a-b)/(33*33));
И получаем вывод такой:
v=59259.00000000000000000000000
a=16829556.00000000000000000000000, b=16829556.00000000000000000000000, i=283
a=16888816.00000000000000000000000, b=16888815.00000000000000000000000, i=284
0.73921
Т.е. прибавление фиксированного числа на 284 итерации прибавляет неправильно. Присмотревшись к диапазону чисел замечаем, что это однако близко к 0x1000000, то бишь 2^24, а мантисса у флоата как раз такая же. Далее дорогой гугл приводит нас на не менее дорогой StackOverflow, так же не менее дорого Джоэла Спольски, а уже там нам старшие товарищи подсказывают вот что:
Ну, в общем, я тоже не допёр сам, хотя мог бы... Получается это как раз тот случай, когда "лучше сладко проспать утро понедельника и выспаться, чем провести всю неделю отлаживая код, написанный в понедельник утром" ;)))
Спасибо за полезную задачку, мне с флоатингом тоже дел много иметь приходится, и я тоже немного знаю теорию, но вот практика - да, практика всё, а пока с такими вещами похоже не сталкивался)
У меня это место подетектилось только когда я в варез загнал
У меня это место подетектилось только когда я в варез загнал заранее известные *константные* значение (то самое 59259).
Так как там минимум-максимум-среднее выводятся рядом, то вот оно и вылезло.
бинарное сложение
практикуют с этой целью маньякусы.
Т.е. из 2**К чисел получают 2**(К-1) промежуточных сумм (попарных) итд итп ипкнх.
немного не по
немного не по теме:
http://en.wikipedia.org/wiki/Kahan_summation_algorithm