Поиск битов в битборде

Тема в разделе "Машинное отделение", создана пользователем WildCat, 25 май 2007.

  1. TopicStarter Overlay

    WildCat Коршунов Игорь

    • Команда форума
    Рег.:
    04.05.2006
    Сообщения:
    3.599
    Симпатии:
    4
    Репутация:
    0
    Адрес:
    Гомель
    Оффлайн
    Мне для покера нужно реализовать поиск бита в битборде. Вроде у нас тут есть парочка спецов по битбордам. Чего посоветуете?

    Вот самый простой вариант, как мне кажется:
    Код:
    int FirstBit8[256];
    
    void InitFirstBit()
    {
        for (int i = 0; i < 256; i++)
        {
            int p = i;
            FirstBit8[i] = 0;
            for (int j = 0; j < 8; j++)
            {
                if (p & 1)
                {
                    FirstBit8[i] = j;
                    break;
                }
                p >>= 1;
            }
        }
    }
    
    int ExtractBit(uint64 v)
    {
        unsigned char *p = (unsigned char*)&v;
        for (int i = 0; i < 8; i++)
        {
            if (p[i])
            {
                int n = FirstBit8[p[i]];
                p[i] &= ~(1 << n);
                return i * 8 + n;
            }
        }
        return 0;
    }
    Можно еще перейти на 16-битный массив. Есть ли какие принципиально иные подходы?
  2. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.491
    Симпатии:
    3.120
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Вот самый простой вариант для поиска наименьшего (самого правого) установленного бита, с одновременной установкой его в ноль:

    Код:
    static const FLD LSB_Magic[64] = 
    {
       A8, B4, E1, H5, E8, B2, E2, G5,
       D8, H4, F7, G2, A7, E3, C3, F5,
       C8, C4, F1, C7, E7, A3, G6, F3,
       H8, D4, G1, E6, B6, E4, H1, E5,
       B8, A4, F8, D1, C1, G7, B7, B1,
       A2, D7, D2, H6, A1, F6, C6, H3,
       G4, G8, H7, C2, F2, A5, H2, D6,
       D3, A6, B5, B3, G3, C5, D5, F4
    };
    
    #define pop_lsb(x)  pop_lsb_inner(&x)
    
    static inline FLD pop_lsb_inner(U64* pb)
    {
       if (*pb == 0)
          return NF;
    
       U64 lsb = *pb ^ (*pb - 1);
       unsigned int foldedLSB = ((int) lsb) ^ ((int)(lsb>>32));
       int ind = (foldedLSB * 0x78291ACF) >> (32-6); // range is 0..63
    
       *pb &= ~lsb;
       return LSB_Magic[ind];
    }
    Эта функция не использует ни одной условной операции (ну ладно, только одну - но зато самую часто срабатывающую), требует не очень много дорогих 64-битных операций, и работает практически так же быстро, как и ассемблерные реализации - но при этом написана на чистом Си!
  3. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
  4. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.491
    Симпатии:
    3.120
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Вообще, на эту тему очень много написано и на WB-форуме, например:
    http://wbforum.vpittlik.org/viewtopic.php?t=3141

    Ну, или в локальный поиск WB-форума - по запросам LSB, FirstOne, magic, de Bruijn и т.п.
  5. TopicStarter Overlay

    WildCat Коршунов Игорь

    • Команда форума
    Рег.:
    04.05.2006
    Сообщения:
    3.599
    Симпатии:
    4
    Репутация:
    0
    Адрес:
    Гомель
    Оффлайн
    Мне кажется более интересным попробовать использовать BSR и BSF. Только покажите как в Си делать ассемблерные вставки (я никогда этм не занимался).

    Кстати, есть инфа о том, насколько быстро работают BSR и BSF?
  6. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.491
    Симпатии:
    3.120
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Несколько лет назад я пробовал - выигрыш в скорости поиска от ассемблерной реализации порядка единиц процентов. Иногда и вообще ноль.

    Отказался из-за проблем с портированием, не хотелось для разных компиляторов писать разные функции - у gcc синтаксис ассемблера AT&T, а у MSVC - интеловский. Опять же, юниксовые версии могут вообще на какой-нибудь Альфе запускаться. В общем, получилось бы как у Крафти, универсально, но развесисто и нечитаемо :)
  7. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
    Это отсюда:
    http://forum.orenlinux.ru/index.php?topic=271.40

    Так-же есть информация что это самые медленные операции на Pentium/PentumMMX.
    от 7 до 73 тактов! 7 тактов инициализация, и по 2 такта на каждый бит сканирования.

    По более новым процам информацию пока не нашел.
  8. TopicStarter Overlay

    WildCat Коршунов Игорь

    • Команда форума
    Рег.:
    04.05.2006
    Сообщения:
    3.599
    Симпатии:
    4
    Репутация:
    0
    Адрес:
    Гомель
    Оффлайн
    Деление должно быть медленней :)
  9. TopicStarter Overlay

    WildCat Коршунов Игорь

    • Команда форума
    Рег.:
    04.05.2006
    Сообщения:
    3.599
    Симпатии:
    4
    Репутация:
    0
    Адрес:
    Гомель
    Оффлайн
    Ладно, я посмотрю как на скорости скажется переход от 8 бит к 16. И тогда будет видно стоит ли это дальнейших оптимизаций.
  10. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
    Это к тому что у меня в шашечной ОФ деление в цикле? :)
    Деление 32битных целых чисел в Pentium (div,idiv) чуть больше 40-ка тактов.
  11. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
  12. TopicStarter Overlay

    WildCat Коршунов Игорь

    • Команда форума
    Рег.:
    04.05.2006
    Сообщения:
    3.599
    Симпатии:
    4
    Репутация:
    0
    Адрес:
    Гомель
    Оффлайн
    На винбордном форуме вроде решили, что лучше не связываться с ассемблерными вставками, а вполне нормально можно сделать на Си через таблицы.
  13. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
    Закачал документацию по Athlon64.
    64-битный bsf выполняется за 9 тактов.
    Скорей всего быстрее сделать невозможно.
  14. Counter Учаcтник

    • Участник
    Рег.:
    21.01.2007
    Сообщения:
    23
    Симпатии:
    0
    Репутация:
    0
    Оффлайн
    int FirstOne(UInt64 value)
    {
    __asm
    {
    bsf eax, dword ptr value
    jnz l
    bsf eax, dword ptr value + 04h
    add eax, 20h
    l:
    }
    }

    int PopFirstOne(UInt64 &value)
    {
    int firstOne = FirstOne(value);
    value &= value - 1;
    return firstOne;
    }
  15. NS Нефёдов Сергей

    • Заслуженный
    • Ветеран
    • Старожил
    Рег.:
    02.05.2006
    Сообщения:
    6.811
    Симпатии:
    96
    Репутация:
    3
    Адрес:
    Санкт-Петербург
    Оффлайн
    А почему не сделать так-же?
    btr, 2 такта.
  16. Booot Учаcтник

    • Участник
    Рег.:
    05.06.2006
    Сообщения:
    140
    Симпатии:
    0
    Репутация:
    0
    Оффлайн
    Я пользуюсь BSF и BSR. Просто потому что мне так оказалось удобнее. Тащить таблицы только из-за того, что лень ассемблер вставлять? Но правда у меня движок на Делфи написан стало быть лишней головной боли с перенесением его на другую платформу быть не должно за не имением :)
  17. Counter Учаcтник

    • Участник
    Рег.:
    21.01.2007
    Сообщения:
    23
    Симпатии:
    0
    Репутация:
    0
    Оффлайн
    А про btr я не знал :) Можно попробовать.
  18. WinPooh В.М.

    • Команда форума
    Рег.:
    13.02.2006
    Сообщения:
    9.491
    Симпатии:
    3.120
    Репутация:
    95
    Адрес:
    Москва
    Оффлайн
    Всем хорош такой код, только вот при попытке заинлайнить эту функцию компилятор (gcc, во всяком случае) начинает ругаться на повторное определение метки l: :(
  19. Vlad_Imir Новичок

    • Новичок
    Рег.:
    12.11.2006
    Сообщения:
    77
    Симпатии:
    284
    Репутация:
    20
    Адрес:
    Россия
    Оффлайн
    Код:
        BYTE  inline GetLastBit(INT_64 line)
        {
            __asm {
                bsr rax, qword ptr line
            }
        }
        BYTE  inline GetFirstBit(INT_64 line)
        {
            __asm {
                bsf rax, qword ptr line
            }
        }
    Использую для 64 битной версии, MS Visual Studio 2005 + Intel Compiller
  20. Осипов Юрий Учаcтник

    • Участник
    Рег.:
    18.06.2007
    Сообщения:
    399
    Симпатии:
    475
    Репутация:
    11
    Адрес:
    Правда
    Оффлайн
    В свете вышеизложенного 64-битного кода.
    Было выпущено несколько 64-битных версий Стрелки. Интересно, догадались эти компилировщики изменить функции first_one и last_one, а заодно popcnt, или скомпилировали как есть?
    Был бы я таким специалистом по дизассемблированию, как обо мне думают, то проверил бы. Может, кто-то знает, что было сделано?
  21. Bison Учаcтник

    • Участник
    Рег.:
    18.01.2008
    Сообщения:
    49
    Симпатии:
    0
    Репутация:
    0
    Оффлайн
    Думаю, что как есть просто не скомпилировалось бы... Синтаксис 64-битного ассемблера другой
  22. bankuss Александр

    • Заслуженный
    • Участник
    • Старожил
    Рег.:
    24.05.2006
    Сообщения:
    1.084
    Симпатии:
    38
    Репутация:
    6
    Оффлайн
    Осипов Юрий, 64 битная студия исходный код "Стрелки" не компилирует! Ошибка выдается как раз на 32-разрядные асм-вставки. Переделав их на х64 все компилируется прекрасно.
  23. Осипов Юрий Учаcтник

    • Участник
    Рег.:
    18.06.2007
    Сообщения:
    399
    Симпатии:
    475
    Репутация:
    11
    Адрес:
    Правда
    Оффлайн
    Непонятно - откуда такая дискриминация.
    Я не знаю, в чем специфика 64-битных приложений.
    Но в 32-битных всегда допускались операции с 16-разрядными и 8-разрядными данными.
    На что может ругаться 64-битный компилятор, если встречает операцию над 32-битными данными?
  24. bankuss Александр

    • Заслуженный
    • Участник
    • Старожил
    Рег.:
    24.05.2006
    Сообщения:
    1.084
    Симпатии:
    38
    Репутация:
    6
    Оффлайн
    Осипов Юрий видимо опкоды х64 другие и студия ругается на это.

Поделиться этой страницей