URL: https://www.opennet.me/cgi-bin/openforum/vsluhboard.cgi
Форум: vsluhforumID9
Нить номер: 8466
[ Назад ]

Исходное сообщение
"Использование NaN, inf как маркеров инициализации переменных"

Отправлено ghostinmachine , 07-Окт-09 21:15 
Здравствуйте.
В своих программах (числодробилки) мне приходиться иногда ставить маркеры неинециализированлости значения переменных. Есть идея применять константы типа NaN, Inf для обозначения таких чисел т.к. их легко отслеживать при отладке/запуске приложения. Вопрос в том грозит ли это чем-то самому коду (быстродействию, переносимости и т.п.) и как корректно присваивать такие значения переменным (скажем без деления на ноль) т.к. в манах нашел только проверку этих констант.
Спасибо.  

Содержание

Сообщения в этом обсуждении
"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 07-Окт-09 23:33 
С какой стати это должно чем-то грозить? Использование пограничных значений float'ов может даже прибавить скорости, если позволит выкинуть проверки каких-то флагов и избавиться таким образом от ветвлений. Другое дело, если у вас вдруг будет isnanf вызываться в каком-нибудь внутреннем цикле (что теоретически может быть медленее проверки флага) - но в таком случае можно порекоммендовать только больше никогда не писать числодробилки.
Что касается переносимости, в math.h определены все нужные константы, в частности NAN и INFINITY, точно это посмотреть можно в стандартах. Люниксовый math.h отсылает напрямую к

/*
*  ISO C99 Standard: 7.12 Mathematics  <math.h>
*/


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено pavlinux , 08-Окт-09 23:35 
>Здравствуйте.
>В своих программах (числодробилки) мне приходиться иногда ставить маркеры неинециализированлости значения переменных.
>Есть идея применять константы типа NaN, Inf для обозначения таких чисел
>т.к. их легко отслеживать при отладке/запуске

А толку,  НАН в дебугере светится как 0.0000, INF как 1.00000


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 12-Окт-09 14:20 
>А толку,  НАН в дебугере светится как 0.0000, INF как 1.00000

Ну да, а 0xFF как 1, а 0 как 0xdeadbeef. Не пори чушь.

float a = NAN, b = INFINITY;
---
(gdb) print a
$1 = nan(0x400000)
(gdb) print b
$2 = inf


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено pavlinux , 12-Окт-09 15:41 
>[оверквотинг удален]
>
>Ну да, а 0xFF как 1, а 0 как 0xdeadbeef. Не пори
>чушь.
>
>float a = NAN, b = INFINITY;
>---
>(gdb) print a
>$1 = nan(0x400000)
>(gdb) print b
>$2 = inf

Докажи что это переменная "a", а не переполнение или не глюк (ядра, оперативки, проца, gdb )

А млин, и правда работает

Starting program: /tmp/a.out ;
main () at test.c:11
11       a = NAN; b = INFINITY;
(gdb) print a
$1 = 0
(gdb) print b
$2 = 0
(gdb) step
13      return 0;
(gdb) print b
$3 = inf
(gdb) print a
$4 = nan(0x400000)
(gdb) step
14      }
(gdb) step
0x00007f2804938b54 in __libc_start_main () from /lib64/libc.so.6


А в Netbeans сцука, именно 1.000 и 0.000 показывает.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено svn , 13-Окт-09 10:33 
>А в Netbeans сцука, именно 1.000 и 0.000 показывает.

В нем вообще очень слабый отладчик С программ. Даже с сигналами работать не умеет.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено ghostinmachine , 13-Окт-09 19:04 
>
>Докажи что это переменная "a", а не переполнение или не глюк (ядра,
>оперативки, проца, gdb )
>

Это не важно, если всплыл маркер - значит с кодом проблема, надо отлаживать.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 13-Окт-09 20:01 
>Докажи что это переменная "a", а не переполнение или не глюк (ядра,
>оперативки, проца, gdb )

Тяжелый случай.

>А в Netbeans сцука, именно 1.000 и 0.000 показывает.

На бейсике пиши.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено f00l , 13-Окт-09 08:18 
>Вопрос в том грозит
>ли это чем-то самому коду (быстродействию, переносимости и т.п.)

Использование float и double в коде ведет к существенному замедлению работы программы. И когда нужна скорость выполнение применять не  следует.

P.S. да и вобше формат float бесполезный, всегда обходился без него. всего 6 значаших чисел, абсолютной точности нет , а 6 разрядов можно и через int обрабатывать .    


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено ghostinmachine , 13-Окт-09 18:59 
>>Вопрос в том грозит
>>ли это чем-то самому коду (быстродействию, переносимости и т.п.)
>
>Использование float и double в коде ведет к существенному замедлению работы программы.
>И когда нужна скорость выполнение применять не  следует.
>
> P.S. да и вобше формат float бесполезный, всегда обходился без него.
>всего 6 значаших чисел, абсолютной точности нет , а 6 разрядов
>можно и через int обрабатывать .

Интересное ответвление: каков приюлизительно прирост производительности при переходе от float к int на AMD( Intell) x86_64? ведь надо покрывать проверку переполнения int, компенсирует ли?


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 13-Окт-09 19:59 
См. ниже и не слушай идиотов.

"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 13-Окт-09 19:58 
>Использование float и double в коде ведет к существенному замедлению работы программы.
>И когда нужна скорость выполнение применять не  следует.

Вообще-то, наоборот. Вот простой alpha blend.

#include <stdio.h>
#include <stdlib.h>
#include <sys/limits.h>
#include <sys/types.h>

#define SIZE    1024*1024
#define ITERS   512

#if defined FLOAT
# define TYPE float
#elif defined DOUBLE
# define TYPE double
#elif defined SHORT
# define TYPE unsigned short
# define MAX USHRT_MAX
#elif defined INT
# define TYPE unsigned int
# define MAX UINT_MAX
#else
#error please define FLOAT, DOUBLE, SHORT or INT
#endif

int main() {
        int i,j;
        srand(234234234);

        TYPE color1[SIZE];
        TYPE color2[SIZE];
        TYPE alpha[SIZE];
        TYPE output[SIZE];

        for (i = 0; i < SIZE; ++i) {
#if defined(FLOAT) || defined(DOUBLE)
                color1[i] = (float)rand()/(float)RAND_MAX;
                color2[i] = (float)rand()/(float)RAND_MAX;
                alpha[i] = (float)rand()/(float)RAND_MAX;
#else
                color1[i] = MAX*(float)rand()/(float)RAND_MAX;
                color2[i] = MAX*(float)rand()/(float)RAND_MAX;
                alpha[i] = MAX*(float)rand()/(float)RAND_MAX;
#endif
        }

        for (j = 0; j < ITERS; ++j)
                for (i = 0; i < SIZE; ++i)
#if defined(FLOAT) || defined(DOUBLE)
                        output[i] = (color1[i]*alpha[i] + color2[i]*(1-alpha[i]));
#elif defined(INT)
                        output[i] = ((uint64_t)color1[i]*alpha[i] + (uint64_t)color2[i]*(MAX-alpha[i]))/MAX;
#else
                        output[i] = (color1[i]*alpha[i] + color2[i]*(MAX-alpha[i]))/MAX;
#endif

#if defined(FLOAT) || defined(DOUBLE)
        printf("blend(%.4f, %.4f, %.4f) = %.4f\n", color1[0], color2[0], alpha[0], output[0]);
#else
        printf("blend(%.4f, %.4f, %.4f) = %.4f\n",
                        (float)color1[0]/(float)MAX,
                        (float)color2[0]/(float)MAX,
                        (float)alpha[0]/(float)MAX,
                        (float)output[0]/(float)MAX);
#endif

        return 0;
}

Вот так оно работает на 64bit машине. Как видите float всех рвет. Не буду приводить результат на 32бин машине, ибо 64бит арифметика убивает там все вообще нахрен (а без нее будем терять точность).

% make test
cc -O2 test.c -DFLOAT -o float
cc -O2 test.c -DDOUBLE -o double
cc -O2 test.c -DSHORT -o short
cc -O2 test.c -DINT -o int
time ./float
blend(0.2036, 0.0478, 0.8507) = 0.1803
        1,87 real         1,87 user         0,00 sys
time ./double
blend(0.2036, 0.0478, 0.8507) = 0.1803
        3,74 real         3,68 user         0,02 sys
time ./short
blend(0.2036, 0.0478, 0.8507) = 0.1803
        2,03 real         2,03 user         0,00 sys
time ./int
blend(0.2036, 0.0478, 0.8507) = 0.1803
        2,20 real         2,15 user         0,03 sys

> P.S. да и вобше формат float бесполезный, всегда обходился без него.
>всего 6 значаших чисел, абсолютной точности нет , а 6 разрядов
>можно и через int обрабатывать .

Да и вообще, вы ламер, хотя бы из-за категоричности высказываний и из-за бреда с 6 значащими числами (что вы вообще в виду имели?). Для любой задачи почти всегда можно точно сказать, что лучше использовать - float, fixed point или свою реализацию с произвольной точностью.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено f00l , 14-Окт-09 08:45 
>>Использование float и double в коде ведет к существенному замедлению работы программы.
>>И когда нужна скорость выполнение применять не  следует.
>
>Вообще-то, наоборот. Вот простой alpha blend.

Пример не корректный. при работе с int зачем то идет преобразование во float, если работаешь с int так и работай. Идет лишняя операция вот и падение производительности.
И потом тест длительностью 2 сек не о чем не говорит.
Вот сделай преобразование Фурье во float и int и прогони 10 мин звуковой информации вот там и увидишь реальную производительность.

>Да и вообще, вы ламер, хотя бы из-за категоричности высказываний и из-за
>бреда с 6 значащими числами (что вы вообще в виду имели?).
>Для любой задачи почти всегда можно точно сказать, что лучше использовать
>- float, fixed point или свою реализацию с произвольной точностью.

Читай внимательно стандарт IEEE 754. (Стандарты читать полезно)

Практически в любой задачи можно обойтись без float. Это просто нужно понимать задачу.

P.S. хотя есть процессоры где поддержка стандарта float реализована аппаратно там применение обосновано.    


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 14-Окт-09 15:25 
> Пример не корректный.

Более, чем корректный.

>при работе с int зачем то идет преобразование
>во float, если работаешь с int так и работай.

Это называется fixed point, неуч. Числа только выводятся как float, чтобы результат одинаково выглядел.

>Идет лишняя операция вот и падение производительности.

Потеря в генерации и распечатке, когда blend выполняется в 512 раз больше? Не смеши.

>И потом тест длительностью 2 сек не о чем не говорит.

Бгыгы. Ну поменяй константы, ты же можешь. Вот с размером 1024 и миллионом итераций:

time ./float
blend(0.2036, 0.0478, 0.8507) = 0.1803
        1,99 real         1,99 user         0,00 sys
time ./double
blend(0.2036, 0.0478, 0.8507) = 0.1803
        2,02 real         2,02 user         0,00 sys
time ./short
blend(0.2036, 0.0478, 0.8507) = 0.1803
        3,77 real         3,77 user         0,00 sys
time ./int
blend(0.2036, 0.0478, 0.8507) = 0.1803
        3,71 real         3,71 user         0,00 sys
nice make test  11,66s user 0,05s system 92% cpu 12,644 total

Инты сливают еще больше.

> Вот сделай преобразование Фурье во float и int и прогони 10
>мин звуковой информации вот там и увидишь реальную производительность.

Думаешь, не делал? Какие там вообще инты нахрен? Возьми fftw3 и посмотри как там сделано и почему, если не веришь.

> Практически в любой задачи можно обойтись без float. Это просто нужно
>понимать задачу.

Ну разумеется, можно ведь написать свой класс на интах вместо FPU. Ты всегда так делаешь?

>P.S. хотя есть процессоры где поддержка стандарта float реализована аппаратно там применение
>обосновано.

Да, всем понятно что ты слил. Понимаешь, весь мир считает floating point на, как ни странно, FPU, а не ищет как заменить его на более торнозные инты.


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено f00l , 14-Окт-09 11:15 
Еще немного:
В данном коде видна основная ошибка, человек мыслит как  математик а не как программист,
если есть задание получать числа в диапазоне от 0.0000 до 0.9999 то нужно работать с float по другому представить нельзя.
а если идет хранение в int, то идет постоянное преобразование, это медленно.

немного переработанный код:
int main(int argc, char * argv[])
{
  srand(234234234);
  for (i = 0; i < SIZE; ++i) {
     color1[i] = rand()/(RAND_MAX/9999);
     color2[i] = rand()/(RAND_MAX/9999);
     alpha[i] = rand()/(RAND_MAX/9999);
  }
   for (j = 0; j < ITERS; ++j)
     for (i = 0; i < SIZE; ++i)
        output[i] = (color1[i]*alpha[i] + color2[i]*(10000-alpha[i]));

    printf("blend(%.4f, %.4f, %.4f) = %.4f\n",
          (float)color1[0]/(float)10000,
          (float)color2[0]/(float)10000,
          (float)alpha[0]/(float)10000,
          (float)output[0]/(float)10000);
    return 0;
}

и результаты на 32 бит машине.

c int
~/work/test/float :> time ./int
blend(0.7010, 0.8640, 0.9905) = 0.7025
2.80user 0.01system 0:02.84elapsed 98%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+4230minor)pagefaults 0swaps

~/work/test/float :> time ./float
blend(0.7011, 0.8641, 0.9906) = 0.7026
2.95user 0.01system 0:03.03elapsed 97%CPU (0avgtext+0avgdata 0maxresident)k
0inputs+0outputs (0major+4229minor)pagefaults 0swaps

получили немного лучший результат. но идет падением точности.

P.S. значения получились другие наверно машина 32 бит


"Использование NaN, inf как маркеров инициализации переменных"
Отправлено аноним , 14-Окт-09 15:37 
>В данном коде видна основная ошибка, человек мыслит как  математик а
>не как программист

Ничего подобного.

>если есть задание получать числа в диапазоне от 0.0000 до 0.9999 то
>нужно работать с float по другому представить нельзя.

Ой, как же так, float ведь не нужен?

>а если идет хранение в int, то идет постоянное преобразование, это медленно.

Еще раз - где там преобразования? Если ты про из float и в начале и во float в конце, я уже сказал что это бред. Где еще?

>получили немного лучший результат. но идет падением точности.

Что за машина? Когда-то FPU вообще был отдельно от процессора, вот там float'ы действительно были медленнее. У тебя такой?
Я тестирую на core2duo, и 32 бита и 64. Вот тебе float, double и int на 32 битах, SIZE=1024, ITERS=1024*1024, чтобы тестировать числодробилку, а не память. Для int MAX=65535, чтобы не было вообще никаких преобразований, int64_t соответственно убран.

time ./float
blend(0.2036, 0.0478, 0.8507) = 0.1803
        1.37 real         1.37 user         0.00 sys
time ./double
blend(0.2036, 0.0478, 0.8507) = 0.1803
        1.38 real         1.38 user         0.00 sys
time ./int
blend(0.2036, 0.0478, 0.8507) = 0.1803
        2.03 real         2.02 user         0.00 sys

Дальше спорить будешь?