Re: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 10:58
Оценка: -2
Кстати, почему-то никто не обратил внимание на алгоритмическую "дебильность" CalcNumOfBits.
Сущесвует множество методов быстрого решения этой проблемы — как для общих случаев, так и для разреженных слов. Понятно, что "вживую" вспоминать эти алгоритмы заставлять по меньшей мере глупо (хотя ничего сложного там нет — обычное групповое сложение, в самом просто варианте), но вот в комментах написать, что это просто набросок и настоящая реализация так не должна работать, имхо, стОило.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[3]: Помогите оценить код
От: Кодт Россия  
Дата: 28.08.07 11:06
Оценка:
Здравствуйте, <Аноним>, Вы писали:

А>В 7-ой студии это сехи ловит


... если ключик указать. И в любой другой, если потанцевать с бубном.
... << RSDN@Home 1.2.0 alpha rev. 655>>
Перекуём баги на фичи!
Re[2]: Помогите оценить код
От: Аноним  
Дата: 28.08.07 11:23
Оценка: +2
Здравствуйте, Andrew S, Вы писали:

AS>Кстати, почему-то никто не обратил внимание на алгоритмическую "дебильность" CalcNumOfBits.

AS>Сущесвует множество методов быстрого решения этой проблемы — как для общих случаев, так и для разреженных слов. Понятно, что "вживую" вспоминать эти алгоритмы заставлять по меньшей мере глупо (хотя ничего сложного там нет — обычное групповое сложение, в самом просто варианте), но вот в комментах написать, что это просто набросок и настоящая реализация так не должна работать, имхо, стОило.

не нужно слов — покажите на примере!
Re[3]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 12:11
Оценка: 9 (2) :)
AS>>Кстати, почему-то никто не обратил внимание на алгоритмическую "дебильность" CalcNumOfBits.
AS>>Сущесвует множество методов быстрого решения этой проблемы — как для общих случаев, так и для разреженных слов. Понятно, что "вживую" вспоминать эти алгоритмы заставлять по меньшей мере глупо (хотя ничего сложного там нет — обычное групповое сложение, в самом просто варианте), но вот в комментах написать, что это просто набросок и настоящая реализация так не должна работать, имхо, стОило.

А>не нужно слов — покажите на примере!


Генри Уоррен Младший, страницы 75-76. Учите матчасть.

int pop (unsigned X)
{
    X = X - ( (X >> 1) & 0x55555555);
    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
    X = (X + (X >> 4)) & 0x0F0F0F0F;
    X = X + (X >> 8) ;
    X = X + (X>> 16) ;
    return X & 0x0000003F;
}
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 12:27
Оценка:
А Егор-то с чем не согласен, или просто так, пнуть из принципа? А может, демонстрируем незнание простейших bittricks?
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[2]: Помогите оценить код
От: Erop Россия  
Дата: 28.08.07 12:57
Оценка: +1
Здравствуйте, Andrew S, Вы писали:

AS>но вот в комментах написать, что это просто набросок и настоящая реализация так не должна работать, имхо, стОило.


ИМХО глупо требовать от кандидата писать всякую хрнеь в комментах.
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[3]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 13:07
Оценка:
AS>>но вот в комментах написать, что это просто набросок и настоящая реализация так не должна работать, имхо, стОило.

E>ИМХО глупо требовать от кандидата писать всякую хрнеь в комментах.


Речь идет о знании алгоритмов (не их реализации, а вообще существовании), а не "хрени в комментах". Из моего сообщения это очевидно.
В общем, понятно, опять адеквата не увидим.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: Помогите оценить код
От: Roman Odaisky Украина  
Дата: 28.08.07 13:10
Оценка: 1 (1) +1
Здравствуйте, Andrew S, Вы писали:

AS>Генри Уоррен Младший, страницы 75-76. Учите матчасть.


AS>
AS>int pop (unsigned X)
AS>{
AS>    X = X - ( (X >> 1) & 0x55555555);
AS>    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
AS>    X = (X + (X >> 4)) & 0x0F0F0F0F;
AS>    X = X + (X >> 8) ;
AS>    X = X + (X>> 16) ;
AS>    return X & 0x0000003F;
AS>}
AS>

Ужас.

unsigned char const ones[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, . . . };

unsigned countOnes(uint32_t x)
{
    return 0
        + ones[(x >>  0) & 0xFF]
        + ones[(x >>  8) & 0xFF]
        + ones[(x >> 16) & 0xFF]
        + ones[(x >> 24) & 0xFF]
    ;
}
До последнего не верил в пирамиду Лебедева.
Re[5]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 14:01
Оценка: :)
AS>>Генри Уоррен Младший, страницы 75-76. Учите матчасть.
AS>>
AS>>int pop (unsigned X)
AS>>{
AS>>    X = X - ( (X >> 1) & 0x55555555);
AS>>    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
AS>>    X = (X + (X >> 4)) & 0x0F0F0F0F;
AS>>    X = X + (X >> 8) ;
AS>>    X = X + (X>> 16) ;
AS>>    return X & 0x0000003F;
AS>>}
AS>>

RO>Ужас.

Нет. Ужас то, что привели вы, почему — см. ниже. Хотя даже если был бы приведен такой вариант — уже значительно лучше цикла.
RO>
RO>unsigned char const ones[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, . . . };

RO>unsigned countOnes(uint32_t x)
RO>{
RO>    return 0
RO>        + ones[(x >>  0) & 0xFF]
RO>        + ones[(x >>  8) & 0xFF]
RO>        + ones[(x >> 16) & 0xFF]
RO>        + ones[(x >> 24) & 0xFF]
RO>    ;
RO>}
RO>


Этот код как минмум не быстрее приведенного мной. Например, на моем А64 — в 2 раза медленее.

        LONGLONG l = QueryPerformanceCounter();
        for (unsigned i = 0; i < 1024*1024;++i)
        {
            pop(i);
        }
        LONGLONG l1 = QueryPerformanceCounter() - l;
        l = QueryPerformanceCounter();
        for (unsigned j = 0; j < 1024*1024;++j)
        {
            countOnes(j);
        }
        LONGLONG l2 = QueryPerformanceCounter() - l;
        cout << (unsigned)l1 << endl;
        cout << (unsigned)l2 << endl;        
// output
23065
42916

Не говоря уже требовании наличия инициализированного не нулями массива (что как минимум увеличивает размер бинарника). Ваш код можно ускорить, если выбирать не char, а unsigned, примерно в 1.5 раза. Но и в этом случае лучше приведенного мной варианта он не стант, а памяти потребует еще больше.
В общем, не стОит считать себя умнее людей, которые алгоритмами оптимизации занимаются профессионально (я имею в виду указанного выше автора, ессно). А почитать указанную книгу как минимум не вредно, а на самом деле — очень полезно.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: Помогите оценить код
От: Аноним  
Дата: 28.08.07 14:04
Оценка:
AS>
AS>int pop (unsigned X)
AS>{
AS>    X = X - ( (X >> 1) & 0x55555555);
AS>    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
AS>    X = (X + (X >> 4)) & 0x0F0F0F0F;
AS>    X = X + (X >> 8) ;
AS>    X = X + (X>> 16) ;
AS>    return X & 0x0000003F;
AS>}
AS>


и что, действительно будет быстрее чем обычный цикл вроде
template <typename T>
unsigned int Bits(T value)
{
    unsigned int bits = 0;
    for (; value > 0; value >>= 1)
        bits += (value & 0x1);
        return bits;
}

?

... причем в котором нет привязки к размерности числа
преждевременная оптимизация — корень всех зла... а приведенный мной пример ну НИКАК не тянет на преждевременную пессимизацию %)
Re[5]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 14:15
Оценка: -1
AS>>
AS>>int pop (unsigned X)
AS>>{
AS>>    X = X - ( (X >> 1) & 0x55555555);
AS>>    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
AS>>    X = (X + (X >> 4)) & 0x0F0F0F0F;
AS>>    X = X + (X >> 8) ;
AS>>    X = X + (X>> 16) ;
AS>>    return X & 0x0000003F;
AS>>}
AS>>


А>и что, действительно будет быстрее чем обычный цикл вроде

А>
А>template <typename T>
А>unsigned int Bits(T value)
А>{
А>    unsigned int bits = 0;
А>    for (; value > 0; value >>= 1)
А>        bits += (value & 0x1);
А>        return bits;
А>}
А>

А>?

Да. В 5 раз, для unsigned 32 bit.

22866        // pop
42549        // countones
106870       // bits


А>... причем в котором нет привязки к размерности числа


Из указанного примера можно при желании сделать безразмерный вариант при помощи шаблонов — там вся мысль заключается в групповом сложении. Причем, сложность будет логарифмическая, т.е. если, например, размерность будет больше в 2 раза, вычисление не будет выполняться в 2 раза дольше в отличие от 2-х приведенных тут вариантов.

А>преждевременная оптимизация — корень всех зла... а приведенный мной пример ну НИКАК не тянет на преждевременную пессимизацию %)


Да-да, это любимая фраза всех лентяев и бездельников В данном случае существует уже _готовые_ алгоритмы, которые надо просто применить — т.е. стоимость r&d == 0. Так что это именно преждевременная пессимизация.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[6]: Помогите оценить код
От: CreatorCray  
Дата: 28.08.07 14:45
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>Этот код как минмум не быстрее приведенного мной. Например, на моем А64 — в 2 раза медленее.


ICC 10
P4 630

Колво циклов увеличил до 1024^3 — бо выполняется слишком быстро

15318209580
8983055617

AS>В общем, не стОит считать себя умнее людей, которые алгоритмами оптимизации занимаются профессионально (я имею в виду указанного выше автора, ессно). А почитать указанную книгу как минимум не вредно, а на самом деле — очень полезно.



pop
  00031 8b ee            mov ebp, esi                           ;.\test.cpp:39.6
  00033 d1 ed            shr ebp, 1                             ;.\test.cpp:39.6
  00035 81 e5 55 55 55 
        55               and ebp, 1431655765                    ;.\test.cpp:39.6
$LN9:
  0003b f7 dd            neg ebp                                ;.\test.cpp:39.10
  0003d 03 ee            add ebp, esi                           ;.\test.cpp:39.10
$LN11:
  0003f 8b c5            mov eax, ebp                           ;.\test.cpp:39.6
  00041 25 33 33 33 33   and eax, 858993459                     ;.\test.cpp:39.6
  00046 c1 ed 02         shr ebp, 2                             ;.\test.cpp:39.6
  00049 81 e5 33 33 33 
        33               and ebp, 858993459                     ;.\test.cpp:39.6
  0004f 03 c5            add eax, ebp                           ;.\test.cpp:39.6
  00051 8b f8            mov edi, eax                           ;.\test.cpp:39.6
  00053 c1 ef 04         shr edi, 4                             ;.\test.cpp:39.6
  00056 03 c7            add eax, edi                           ;.\test.cpp:39.6
  00058 25 0f 0f 0f 0f   and eax, 252645135                     ;.\test.cpp:39.6
  0005d 8b e8            mov ebp, eax                           ;.\test.cpp:39.6
  0005f c1 ed 08         shr ebp, 8                             ;.\test.cpp:39.6
  00062 03 c5            add eax, ebp                           ;.\test.cpp:39.6
  00064 8b e8            mov ebp, eax                           ;.\test.cpp:39.6
  00066 c1 ed 10         shr ebp, 16                            ;.\test.cpp:39.6
  00069 03 c5            add eax, ebp                           ;.\test.cpp:39.6
  0006b 83 e0 3f         and eax, 63                            ;.\test.cpp:39.6


countOnes
  0009a 0f b6 e8         movzx ebp, al                          ;.\test.cpp:48.6
  0009d 0f b6 95 00 00 
        00 00            movzx edx, BYTE PTR ?ones$0@@4QBEB[ebp] ;.\test.cpp:48.6
  000a4 8b e8            mov ebp, eax                           ;.\test.cpp:48.6
  000a6 c1 ed 08         shr ebp, 8                             ;.\test.cpp:48.6
  000a9 81 e5 ff 00 00 
        00               and ebp, 255                           ;.\test.cpp:48.6
  000af 0f b6 ad 00 00 
        00 00            movzx ebp, BYTE PTR ?ones$0@@4QBEB[ebp] ;.\test.cpp:48.6
$LN37:
  000b6 03 d5            add edx, ebp                           ;.\test.cpp:48.3
$LN39:
  000b8 8b e8            mov ebp, eax                           ;.\test.cpp:48.6
  000ba c1 ed 10         shr ebp, 16                            ;.\test.cpp:48.6
  000bd 81 e5 ff 00 00 
        00               and ebp, 255                           ;.\test.cpp:48.6
  000c3 0f b6 ad 00 00 
        00 00            movzx ebp, BYTE PTR ?ones$0@@4QBEB[ebp] ;.\test.cpp:48.6
  000ca 03 d5            add edx, ebp                           ;.\test.cpp:48.6
  000cc 8b e8            mov ebp, eax                           ;.\test.cpp:48.6
  000ce c1 ed 18         shr ebp, 24                            ;.\test.cpp:48.6
  000d1 0f b6 ad 00 00 
        00 00            movzx ebp, BYTE PTR ?ones$0@@4QBEB[ebp] ;.\test.cpp:48.6
  000da 8d 1c 2a         lea ebx, DWORD PTR [edx+ebp]           ;.\test.cpp:48.6
... << RSDN@Home 1.1.4 stable SR1 rev. 568>>
Re[6]: Помогите оценить код
От: Аноним  
Дата: 28.08.07 15:15
Оценка:
AS>Из указанного примера можно при желании сделать безразмерный вариант при помощи шаблонов — там вся мысль заключается в групповом сложении. Причем, сложность будет логарифмическая, т.е. если, например, размерность будет больше в 2 раза, вычисление не будет выполняться в 2 раза дольше в отличие от 2-х приведенных тут вариантов.

будьте любезны — уж очень хочется заценить
Re[7]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 15:27
Оценка:
AS>>Этот код как минмум не быстрее приведенного мной. Например, на моем А64 — в 2 раза медленее.

CC>ICC 10

CC>P4 630

CC>Колво циклов увеличил до 1024^3 — бо выполняется слишком быстро


CC>15318209580

CC>8983055617

AS>>В общем, не стОит считать себя умнее людей, которые алгоритмами оптимизации занимаются профессионально (я имею в виду указанного выше автора, ессно). А почитать указанную книгу как минимум не вредно, а на самом деле — очень полезно.

CC>

Да пожалуйста, тоже увеличил.
VC6
23384774
43100993
VC7.1
17996589
20148363


Итого — у меня мой варианта _всегда_ быстрее. Вариант Романа, к сожалению, имеет довольно мало средств для оптимизации — тут практически не могут спариваться команды, да и выборка из памяти дело тормознутое.
Но как собственно VC7 смог так улучшить вариант 2? Посмотрим.

А это мои, VC 7.1
Pop
    mov    ecx, edx
    shr    ecx, 1
    and    ecx, 1431655765                ; 55555555H
    mov    eax, edx
    sub    eax, ecx
    mov    ecx, eax
    shr    ecx, 2
    and    ecx, 858993459                ; 33333333H
    and    eax, 858993459                ; 33333333H
    add    ecx, eax
    mov    eax, ecx
    shr    eax, 4
    add    eax, ecx
    and    eax, 252645135                ; 0f0f0f0fH
    mov    ecx, eax
    shr    ecx, 8
    add    eax, ecx
    mov    ecx, eax
    shr    ecx, 16                    ; 00000010H
    add    ecx, eax
    and    ecx, 63                    ; 0000003fH


countOnes
    lea    edx, DWORD PTR [eax-1]
    mov    ebx, edx
    shr    ebx, 24                    ; 00000018H
    movzx    ebx, BYTE PTR _ones[ebx]
    lea    esi, DWORD PTR [eax-2]
    mov    DWORD PTR tv1199[esp+48], esi
    shr    esi, 24                    ; 00000018H
    movzx    esi, BYTE PTR _ones[esi]
    add    esi, ebx
    lea    ecx, DWORD PTR [eax+1]
    mov    ebx, ecx
    shr    ebx, 24                    ; 00000018H
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    lea    ebx, DWORD PTR [eax-2]
    and    ebx, 255                ; 000000ffH
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    lea    ebx, DWORD PTR [eax-1]
    and    ebx, 255                ; 000000ffH
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    mov    ebx, eax
    shr    ebx, 24                    ; 00000018H
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    movzx    ebx, ah
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    movzx    ebx, BYTE PTR tv1023[esp+50]
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    movzx    ebx, ch
    movzx    ebx, BYTE PTR _ones[ebx]
    mov    DWORD PTR tv1192[esp+48], edx
    add    esi, ebx
    movzx    edx, dh
    movzx    edx, BYTE PTR _ones[edx]
    mov    DWORD PTR tv1180[esp+48], ecx
    movzx    ebx, BYTE PTR tv1180[esp+50]
    movzx    ebx, BYTE PTR _ones[ebx]
    add    esi, ebx
    add    esi, edx
    movzx    edx, BYTE PTR tv1192[esp+50]
    movzx    edx, BYTE PTR _ones[edx]
    add    esi, edx
    movzx    edx, BYTE PTR tv1199[esp+49]
    movzx    edx, BYTE PTR _ones[edx]
    add    esi, edx
    movzx    edx, BYTE PTR tv1199[esp+50]
    movzx    edx, BYTE PTR _ones[edx]
    and    ecx, 255                ; 000000ffH
    movzx    ecx, BYTE PTR _ones[ecx]
    add    esi, edx
    mov    edx, eax
    add    esi, ecx
    and    edx, 255                ; 000000ffH
    movzx    ecx, BYTE PTR _ones[edx]


Как мы видим, тут просто развернули цикл (пачками по 4). Полагаю, IC сделал примерно то же, поскольку больше увеличить производительность в данном варианте нечем (только работать с 32-х битным массивом, но там прибавка не будет большой).
Т.о., сравнение в данном случае получается не слишком некорректным (а точнее, вообще некорретным) — в реальном применении цикл гораздо сложнее и развернуть его таким образом не получится. Правильнее всего в смысле теста поступает VC6 — он тупо компилит то, что ему написали
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[7]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 15:31
Оценка: -3
AS>>Из указанного примера можно при желании сделать безразмерный вариант при помощи шаблонов — там вся мысль заключается в групповом сложении. Причем, сложность будет логарифмическая, т.е. если, например, размерность будет больше в 2 раза, вычисление не будет выполняться в 2 раза дольше в отличие от 2-х приведенных тут вариантов.

А>будьте любезны — уж очень хочется заценить


Что за народ пошел — все только просят привести решение, а подумать самим лень

В общем, даже и не собираюсь — у меня полно других дел, помимо изобретательств никому не нужных шаблонов. Если вам действительно требуется такая функциональность — вы и делайте, где взять алгоритм и объяснение его работы я уже сказал. Из алгоритма возможность его реализации для любых 2^n битных значений вытекает очень явно
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[4]: Помогите оценить код
От: Erop Россия  
Дата: 28.08.07 18:34
Оценка: 2 (2) +2
Здравствуйте, Andrew S, Вы писали:

AS>Речь идет о знании алгоритмов (не их реализации, а вообще существовании), а не "хрени в комментах". Из моего сообщения это очевидно.

1) ИМХО, не важно знает ли кандидат такой алгоритм или нет. Мне лично было бы вполне достаточно, если бы на вопрос "А как это ускорить" он бы ответил что-то вроде: "Вообще-то можно по индексируемой байтом таблице суммировать, или может стоит поискать эффективный алгоритм в интернете. Если это действительно надо ускорять"
2) В любом случе ожидать, что кандидат напишет к своему коду коммент: "можно и быстрее, но я забыл точно как именно" по крайней мере странно...

AS>В общем, понятно, опять адеквата не увидим.

В цело м перед собеседованием всё-таки стоит задаться вопросом чего ты хочешь узнать о кандидате в результате собеседорвания, и вообще чего именно ты от него хочешь...
Все эмоциональные формулировки не соотвествуют действительному положению вещей и приведены мной исключительно "ради красного словца". За корректными формулировками и неискажённым изложением идей, следует обращаться к их автором или воспользоваться поиском
Re[6]: Помогите оценить код
От: Roman Odaisky Украина  
Дата: 28.08.07 19:08
Оценка:
Здравствуйте, Andrew S, Вы писали:

AS>>>Генри Уоррен Младший, страницы 75-76. Учите матчасть.

RO>>Ужас.
AS>Нет. Ужас то, что привели вы, почему — см. ниже. Хотя даже если был бы приведен такой вариант — уже значительно лучше цикла.
RO>>unsigned char const ones[256] = { 0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4, . . . };

AS>Этот код как минмум не быстрее приведенного мной. Например, на моем А64 — в 2 раза медленее.


AS>// output

AS>23065
AS>42916
AS>Не говоря уже требовании наличия инициализированного не нулями массива (что как минимум увеличивает размер бинарника). Ваш код можно ускорить, если выбирать не char, а unsigned, примерно в 1.5 раза. Но и в этом случае лучше приведенного мной варианта он не стант, а памяти потребует еще больше.
AS>В общем, не стОит считать себя умнее людей, которые алгоритмами оптимизации занимаются профессионально (я имею в виду указанного выше автора, ессно). А почитать указанную книгу как минимум не вредно, а на самом деле — очень полезно.

О ужас! 256 байт.

Мой код имеет премущество совсем в другом. По нему понятно, что он делает. Если допустить ошибку в твоем, то можно доолго ее искать. Ну, и premature optimization…

По поводу того, что мой код якобы не имеет возможностей для оптимизации компилятором:
unsigned countOnesSmartly(unsigned X)
{
    X = X - ( (X >> 1) & 0x55555555);
    X = (X & 0x33333333) + ((X >> 2) & 0x33333333);
    X = (X + (X >> 4)) & 0x0F0F0F0F;
    X = X + (X >> 8) ;
    X = X + (X>> 16) ;
    return X & 0x0000003F;
}

unsigned countOnesLamely(unsigned x)
{
    unsigned res = 0;
    while(x)
    {
        x &= x - 1;
        ++res;
    }
    return res;
}

class OnesCounter
{
public:
    OnesCounter()
    {
        for(unsigned i = 0; i < 65536; ++i)
        {
            table[i] = countOnesLamely(i);
        }
    }

    unsigned operator()(unsigned x) const
    {
        return table[x & 0xFFFF] + table[x >> 16];
    }

private:
    unsigned table[65536];
};


template <class F>
inline LONGLONG getLargeInt(F func)
{
    LARGE_INTEGER tmp;
    func(&tmp);
    return tmp.QuadPart;
}

template <class It, class F>
LONGLONG benchmark(It first, It last, F f, unsigned& dummy)
{
    LONGLONG const t1 = getLargeInt(QueryPerformanceCounter);
    while(first != last)
    {
        dummy += f(*first++);
    }
    LONGLONG const t2 = getLargeInt(QueryPerformanceCounter);

    return t2 - t1;
}

int main()
{
    unsigned const sampleSize = 0x08000000;
    std::vector<unsigned> data(sampleSize);

    // Ваши с CreatorCray варианты дают мне поблажку, позволяя менеджеру кеша загружать таблицу по частям.
    std::generate(data.begin(), data.end(), boost::bind(boost::uniform_int<unsigned>(0u, 0xFFFFFFFFu), boost::mt19937()));

    unsigned dummy = 0;

    LONGLONG const tLame  = benchmark(data.begin(), data.end(), countOnesLamely, dummy);
    LONGLONG const tSmart = benchmark(data.begin(), data.end(), countOnesSmartly, dummy);
    LONGLONG const tTable = benchmark(data.begin(), data.end(), OnesCounter(), dummy);

    std::cout << tLame  << std::endl;
    std::cout << tSmart << std::endl;
    std::cout << tTable << std::endl;

    std::cout << (dummy == 42 ? ' ' : '\t') << std::endl;
}


VC8 -Oxb2:
16433597970
5235748897
3936869895

MinGW 3.4.2 -O3:
14762037345
4396007865
2606004375
До последнего не верил в пирамиду Лебедева.
Re[7]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 19:53
Оценка:
RO>О ужас! 256 байт.

Ага, и так на каждый чих? Ну да, верно, поэтому и получаем то, что получаем — гигантские и на 99% бесполезные исполняемые модули...

RO>Мой код имеет премущество совсем в другом. По нему понятно, что он делает. Если допустить ошибку в твоем, то можно доолго ее искать. Ну, и premature optimization…


Тут я согласен. Для этих целей надо просто привести начальный (т.е. цикл со сдвигом) код в комментах функции, либо краткое описание алгоритма — он действительно очень прост.
А сампл.. Ну да, действительно, тут получалась последовательная выборка из таблица, что VC 71 заметил и "наоптимизировал".

RO>По поводу того, что мой код якобы не имеет возможностей для оптимизации компилятором:


\code skipped\

Ну, это уже совсем не весело — 256 кб пустоты для такой мелкой функции. Почему бы тогда уж 4 гб таблицу не сделать?

А по поводу результатов — для начала надо убедиться, что в данном случае сам инструмент измерений не вносит большой погрешности, как в моем варианте с VC71, когда раскручивался цикл. Т.е. смотреть нативный код — надо добиваться, чтобы _всем_ вариантам были предоставлены одинаковые условия. Например, для меня совсем не очевидно, что 256 кб таблица будет быстрее 1 кб — тут уже проблемы с кешем даже второго уровня начнутся.
А нативного кода я тут не приметил

Впрочем, я посмотрел и сам — ну и конечно, там оно и есть, ведь Роман для своего случая передает не просто указатель на функцию (который, ессно, не встраивается), а функтор (который, как раз наоборот, встраивается почти всегда).

Вот, что получается с OnesCounter.
??$benchmark@Viterator@?$vector@IV?$allocator@I@std@@@std@@VOnesCounter >::iterator,OnesCounter>, COMDAT

; 318  : {

    sub    esp, 16                    ; 00000010H
    push    esi
    push    edi

; 319  :     LONGLONG const t1 = getLargeInt(QueryPerformanceCounter);

    mov    edi, DWORD PTR __imp__QueryPerformanceCounter@4
    lea    eax, DWORD PTR _tmp$74373[esp+24]
    push    eax
    call    edi

; 320  :     while(first != last)

    mov    ecx, DWORD PTR _first$[esp+20]
    mov    esi, DWORD PTR _last$[esp+20]
    cmp    ecx, esi
    je    SHORT $L71530
    mov    edx, DWORD PTR _dummy$[esp+20]
    push    ebx
    push    ebp
$L71529:

; 321  :     {
; 322  :         dummy += f(*first++);

    mov    eax, ecx
    mov    eax, DWORD PTR [eax]
    mov    ebx, eax
    and    eax, 65535                ; 0000ffffH
    mov    ebp, DWORD PTR _f$[esp+eax*4+28]
    mov    eax, DWORD PTR [edx]
    shr    ebx, 16                    ; 00000010H
    mov    ebx, DWORD PTR _f$[esp+ebx*4+28]
    add    ebx, ebp
    add    ecx, 4
    add    eax, ebx
    cmp    ecx, esi
    mov    DWORD PTR [edx], eax
    jne    SHORT $L71529
    pop    ebp
    pop    ebx
$L71530:

; 323  :     }
; 324  :     LONGLONG const t2 = getLargeInt(QueryPerformanceCounter);

    lea    ecx, DWORD PTR _tmp$74407[esp+24]
    push    ecx
    call    edi

; 325  : 
; 326  :     return t2 - t1;

    mov    edx, DWORD PTR _tmp$74373[esp+24]
    mov    eax, DWORD PTR _tmp$74407[esp+24]
    mov    ecx, DWORD PTR _tmp$74373[esp+28]
    sub    eax, edx
    mov    edx, DWORD PTR _tmp$74407[esp+28]
    pop    edi
    sbb    edx, ecx
    pop    esi

; 327  : }

    add    esp, 16                    ; 00000010H
    ret    0
??$benchmark@Viterator@?$vector@IV?$allocator@I@std@@@std@@VOnesCounter>::iterator,OnesCounter>


а вот что с остальными измерениями:

??$benchmark@Viterator@?$vector@IV?$allocator@I@std@@@std@@P6AII@Z(__cdecl*)(unsigned int)>, COMDAT

; 318  : {

    sub    esp, 16                    ; 00000010H
    push    ebx
    push    esi

; 319  :     LONGLONG const t1 = getLargeInt(QueryPerformanceCounter);

    lea    eax, DWORD PTR _tmp$74333[esp+24]
    push    eax
    call    DWORD PTR __imp__QueryPerformanceCounter@4

; 320  :     while(first != last)

    mov    esi, DWORD PTR _first$[esp+20]
    mov    ebx, DWORD PTR _last$[esp+20]
    cmp    esi, ebx
    je    SHORT $L71523
    push    ebp
    mov    ebp, DWORD PTR _f$[esp+24]
    push    edi
    mov    edi, DWORD PTR _dummy$[esp+28]
$L71522:

; 321  :     {
; 322  :         dummy += f(*first++);

    mov    eax, esi
    mov    ecx, DWORD PTR [eax]
    push    ecx
    add    esi, 4
    call    ebp
    mov    ecx, DWORD PTR [edi]
    add    ecx, eax
    add    esp, 4
    cmp    esi, ebx
    mov    DWORD PTR [edi], ecx
    jne    SHORT $L71522
    pop    edi
    pop    ebp
$L71523:

; 323  :     }
; 324  :     LONGLONG const t2 = getLargeInt(QueryPerformanceCounter);

    lea    edx, DWORD PTR _tmp$74363[esp+24]
    push    edx
    call    DWORD PTR __imp__QueryPerformanceCounter@4

; 325  : 
; 326  :     return t2 - t1;

    mov    edx, DWORD PTR _tmp$74333[esp+24]
    mov    eax, DWORD PTR _tmp$74363[esp+24]
    mov    ecx, DWORD PTR _tmp$74333[esp+28]
    sub    eax, edx
    mov    edx, DWORD PTR _tmp$74363[esp+28]
    pop    esi
    sbb    edx, ecx
    pop    ebx

; 327  : }

    add    esp, 16                    ; 00000010H
    ret    0
??$benchmark@Viterator@?$vector@IV?$allocator@I@std@@@std@@P6AII@Z(__cdecl*)(unsigned int)>


Хотелось бы думать, что это было сделано непреднамеренно, хотя использование функтора _только_ для своего случая — странно.
Или VC8 для всех случае генерит идентичный код? Если нет — тогда ценность этих измерений == 0...
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[5]: Помогите оценить код
От: Andrew S Россия http://alchemy-lab.com
Дата: 28.08.07 20:06
Оценка:
AS>>Речь идет о знании алгоритмов (не их реализации, а вообще существовании), а не "хрени в комментах". Из моего сообщения это очевидно.
E>1) ИМХО, не важно знает ли кандидат такой алгоритм или нет. Мне лично было бы вполне достаточно, если бы на вопрос "А как это ускорить" он бы ответил что-то вроде: "Вообще-то можно по индексируемой байтом таблице суммировать, или может стоит поискать эффективный алгоритм в интернете. Если это действительно надо ускорять"

Опять передергиваете. Перечитайте то, на что отвечаете, нужное выделено.

E>2) В любом случе ожидать, что кандидат напишет к своему коду коммент: "можно и быстрее, но я забыл точно как именно" по крайней мере странно...


Да при чем тут комменты — смысл в том, что надо понимать, что это далеко не оптимальная реализация. Судя по коду (то, что например, это шаблонная функция), кандидат об этом не задумывался.

AS>>В общем, понятно, опять адеквата не увидим.

E>В цело м перед собеседованием всё-таки стоит задаться вопросом чего ты хочешь узнать о кандидате в результате собеседорвания, и вообще чего именно ты от него хочешь...

Это вопрос не ко мне, а к топиккастеру. Хотя за ту сумму, что он озвучил, откомментировав ее как "средняя по городу вообще (а не для IT)" — думаю, вполне нормально. Хотя, конечно, задания таковы, что по ним определнно сказать что-либо сложно.
http://www.rusyaz.ru/pr — стараемся писАть по-русски
Re[8]: Помогите оценить код
От: Roman Odaisky Украина  
Дата: 28.08.07 21:15
Оценка: +1
Здравствуйте, Andrew S, Вы писали:

AS>Впрочем, я посмотрел и сам — ну и конечно, там оно и есть, ведь Роман для своего случая передает не просто указатель на функцию (который, ессно, не встраивается), а функтор (который, как раз наоборот, встраивается почти всегда).


Почему компиляторы не всегда встраивают вызовы функций по одному и тому же указателю — неясно. Надеюсь, исправятся.

AS>Хотелось бы думать, что это было сделано непреднамеренно, хотя использование функтора _только_ для своего случая — странно.

AS>Или VC8 для всех случае генерит идентичный код? Если нет — тогда ценность этих измерений == 0...

Там потому функтор, что он же должен таблицу проинициализировать.

А вообще, засунул бы функции в классы и проверил бы сам.

Получается интересно:
3872588475 — хитрые битовые операции
3935120400 — таблица unsigned[65536]

Вывод: твою функцию в топку, мою функцию в топку, использовать std::bitset::count, пока не выяснится, что программа проводит в ней непристойно много времени.
До последнего не верил в пирамиду Лебедева.
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.