Русское сообщество по скриптингу

Работа с битами (использование операторов)

Статьи или фрагменты кода для новичков и уже опытных скриптеров по AMXX.

Модератор: Chuvi

Правила форума
1. Запрещено материться и оскорблять других участников форума.
2. Запрещен флуд, оффтоп, дабл постинг во всех разделах форума, кроме раздела "Болтовня".
3. Запрещено взламывать сайт/форум или наносить любой вред проекту.
4. Запрещено рекламировать другие ресурсы.
5. Запрещено создавать темы без информативного названия. Название темы должно отображать ее смысл.

В данном разделе форума разрешено создавать темы, касающие только обучающему материалу по AMX Mod X.

Работа с битами (использование операторов)

Сообщение DJ_WEST » 07 окт 2009, 11:32

Автор: ot_207
Перевод и редактирование: DJ_WEST

Данная статья поможет вам научиться работать с битами через битовые операторы, что даст вам некоторый прирост работы плагина по сравнению с булевыми массивами. Работа с битами быстрее для компьютера, но для понимания кода человеком сложнее.

Что такое битсумма?
Битсумма - это то, на чем основана работа памяти. Память состоит из ячеек (битов), которые могут хранить два значения: 1 и 0. Пример, как хранится число в одном байте (байт = 8 бит):
"8" (обычное число) = "00001000" (число в памяти [1 байт])


Как битсумма работает?
Идея состоит в том, что битсумма позволяет управлять ее позицией. И мы можем проверить имеет ли позиция 1 или 0.

Какие есть операторы и как они работают?
  • Оператор |
    Данный оператор работает, как логический оператор ||, но производит операцию над каждым битом.
    Пример:
    Код: Выделить всё
    first_byte = "10010001" 
    second_byte 
    = "01010001"

    first_byte | second_byte = "11010001"  

    Код: Выделить всё

    |     1      0
    1     1      1
    0     1      0

  • Оператор &
    Данный оператор работает, как логический оператор &&, но производит операцию над каждым битом.
    Пример:
    Код: Выделить всё

    first_byte 
    = "10010001" 
    second_byte 
    = "01010001" 

    first_byte 
    & second_byte = "00010001" 
     

    Код: Выделить всё
    &     1      0
    1     1      0
    0     0      0

  • Оператор ^ (Исключающее ИЛИ)
    Данный оператор работает, как логический оператор ^^, но производит операцию над каждым битом.
    Пример:
    Код: Выделить всё

    first_byte 
    = "10010001" 
    second_byte 
    = "01010001" 

    first_byte 
    ^ second_byte = "11000000" 
     

    Код: Выделить всё

    ^    1      0
    1    0      1
    0    1      0

  • Оператор ~
    Данный оператор отрицает каждый бит, поэтому бит 0 становится 1, а бит 1 становится 0.
    Пример:
    Код: Выделить всё

    first_byte 
    = "10010001" 

    ~first_byte = "01101110" 
     

    Код: Выделить всё

    ~1 = 0
    ~0 = 1

  • Оператор <<
    Данный оператор смещает биты влево на указанное число позиций.
    Например:
    Код: Выделить всё
    "00001100" << 1 = "00011000"  

    Если мы преобразуем полученное число в десятичную систему, то увидем, что в результате получилось число умноженное на 2. Следовательно, 1<<3 будет тоже самое, что 2^3 * 1.
  • Оператор >>
    Данный оператор смещает биты вправо на указанное число позиций.
    Например:
    Код: Выделить всё
    "00000111" >> 3 = "00000000" 
     

Как работают обычные числа?
Числа хранятся в ячейках. Следовательно, числа из десятичной системы преобразуются в двоичную. К примеру, число 9 становится "00001001". Чтобы перобразовать число из двоичной системы в десятичную, нам нужно умножить каждую позицию на число 2 в степени:
00001001: 1*(2^0) + 0*(2^1) + 0*(2^2) + 1*(2^3) + 0*(2^4) + 0*(2^5) + 0*(2^6) + 0*(2^7) = 1 + 8 = 9

Как применить данную статью в моих плагинах?
Мы можем использовать битсуммы вместо булевых массивов.
Примечание: Важно отметить, что если, к примеру, у нас есть 1 = 0000 0000 0000 0000 0000 0000 0000 0001 и выполняя 1 << 32 мы получаем: 1 0000 0000 0000 0000 0000 0000 0000 0000, как видно 1 выходит за пределы. Поэтому при 32 игроках на сервере, мы не получим верную работоспособность. Для этого надо отнять 1. Вместо 1-32 у нас будет 0-31.

К примеру, вместо:
Код: Выделить всё

new bool
: is_alive[33] 
 

Запишем:
Код: Выделить всё

new bitsum_is_alive 


Вместо:
Код: Выделить всё

if 
(is_alive[id]) 
{ 
} 
 

Запишем:
Код: Выделить всё

if 
(bistum_is_alive & (1<<(id-1))) 
{ 
} 
 


Вместо:
Код: Выделить всё
is_alive[id] = true

Код: Выделить всё
is_alive[id] = false

Запишем:
Код: Выделить всё
bitsum_is_alive |= (1<<(id-1)) 

Код: Выделить всё
bitsum_is_alive &=  ~(1<<(id-1)) 


Если рассматривать, к примеру, присвоение:
Код: Выделить всё
is_alive[id] = true

или как мы заменили:
Код: Выделить всё
bitsum_is_alive |= (1<<(id-1)) 

где id = 1 при bitsum_is_alive = 0000 0000 0000 0000 0000 0000 0000 0000, то есть игрок id = 1, первый на сервере.
Вычисления:
Код: Выделить всё

1. id
-= 1-= 0
2. 1
<<(id-1) = 1 << 0 =
0000 0000 0000 0000 0000 0000 0000 0001 << 0 = 0000 0000 0000 0000 0000 0000 0000 0001
3. bitsum_is_alive 
| (1<<(id-1)) = 
0000 0000 0000 0000 0000 0000 0000 0000
|
0000 0000 0000 0000 0000 0000 0000 0001
=
0000 0000 0000 0000 0000 0000 0000 0001
4. bitsum_is_alive 
= bitsum_is_alive | (1<<(id-1)) = 0000 0000 0000 0000 0000 0000 0000 0001


А если допустить, к примеру, что bitsum_is_alive = 0000 0000 0000 0010 0100 0000 0100 0001, что говорит нам о том, что игроки у которых id равно 1, 7, 15, 18 - живы, так как у них бит равен 1, отсчет битов ведется с конца. То присвоение игроку id = 7 (выделенный красный бит) статуса мертвый (бит в 0), будет происходить след. образом (как мы заменяли код выше):
Код: Выделить всё
bitsum_is_alive &=  ~(1<<(id-1)) 

Вычисления:
Код: Выделить всё

1. id
-= 7-= 6
2. 1
<<(id-1) = 1<<=
0000 0000 0000 0000 0000 0000 0000 0001 << 6 = 0000 0000 0000 0000 0000 0000 0100 0000
3. 
~(1<<(id-1)) = 1111 1111 1111 1111 1111 1111 1011 1111
4. bitsum_is_alive 
& ~(1<<(id-1)) = 
0000 0000 0000 0010 0100 0000 0100 0001
&
1111 1111 1111 1111 1111 1111 1011 1111
=
0000 0000 0000 0010 0100 0000 0000 0001
5. bitsum_is_alive 
= bitsum_is_alive & ~(1<<(id-1)) = 0000 0000 0000 0010 0100 0000 0000 0001. 

Мы получили bitsum_is_alive = 0000 0000 0000 0010 0100 0000 0000 0001

Можно ли как-то оптимизировать работу?
Можно сделать stock функцию:
Код: Выделить всё

stock is_user_alive
(id) 
{ 
      return 
(bistum_is_alive & (1<<(id-1))) ? 1 : 0 
} 
 

Или макрос:
Код: Выделить всё
#define is_user_alive(%1) (bistum_is_alive & (1 << (%1-1))) ? 1 : 0 
 
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3641
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2209 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Работа с битами (использование операторов)

Сообщение DJ_WEST » 09 ноя 2010, 08:59

Читай часть:
Как применить данную статью в моих плагинах?
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3641
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2209 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Работа с битами (использование операторов)

Сообщение Skriptar » 10 ноя 2010, 01:15

DJ_WEST, Есть ли способы шифровки имен констант от дисасма ?
На один бит влево или право и строка ... ну ты понял.
Я знаю только то, что я ничего не знаю.
Аватара пользователя
Skriptar
 
Сообщения: 953
Зарегистрирован: 20 окт 2009, 15:34
Благодарил (а): 180 раз.
Поблагодарили: 136 раз.
Языки программирования: Counter-Strike 1.6

Re: Работа с битами (использование операторов)

Сообщение DJ_WEST » 10 ноя 2010, 09:06

Напиши, но любой способ можно также расшифровать. В UCP подобие такого.
Не пишите мне в ЛС: если вам нужна помощь на бесплатной основе. Любые вопросы на форум.
Аватара пользователя
DJ_WEST
Администратор
 
Сообщения: 3641
Зарегистрирован: 22 авг 2009, 00:38
Благодарил (а): 48 раз.
Поблагодарили: 2209 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Counter-Strike: Source
Left 4 Dead
Left 4 Dead 2

Re: Работа с битами (использование операторов)

Сообщение Fedcomp » 13 ноя 2010, 12:03

Прочитал в инете стороннюю статью, понял как с ними работать. Здесь это слаабо доступно для понимания.
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.


"я ставлю зависимости потому что мне приятно" - subb98 @ 2017
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4936
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 813 раз.
Поблагодарили: 1317 раз.
Языки программирования: =>
pawn / php / python / ruby
javascript / rust

Re: Работа с битами (использование операторов)

Сообщение Sho0ter » 13 ноя 2010, 17:53

Сделал простой bits.inc
[pawn]#define _bits_included

new bitsuser;
new 
bits;

stock is_user_bit(id)
{
    if(
bitsuser & (<< (id 1)))
    {
        return 
1;
    }
    return 
0;
}

stock add_user_bit(id)
{
    
bitsuser |= (<< (id 1));
    return 
1;
}

stock remove_user_bit(id)
{
    
bitsuser &= ~(<< (id 1));
    return 
1;
}

stock is_bit(id)
{
    if(
bits & (<< bit))
    {
        return 
1;
    }
    return 
0;
}

stock add_bit(id)
{
    
bits |= (<< bit);
    return 
1;
}

stock remove_bit(id)
{
    
bits &= ~(<< bit);
    return 
1;
[/pawn]
Аватара пользователя
Sho0ter
 
Сообщения: 585
Зарегистрирован: 31 мар 2010, 19:18
Откуда: г. Белая Церковь, Украина
Благодарил (а): 12 раз.
Поблагодарили: 307 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life 1

Re: Работа с битами (использование операторов)

Сообщение Fedcomp » 13 ноя 2010, 18:05

И потерял всю производительность. Правильно делается через #define, charsmax тому пример
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.


"я ставлю зависимости потому что мне приятно" - subb98 @ 2017
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4936
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 813 раз.
Поблагодарили: 1317 раз.
Языки программирования: =>
pawn / php / python / ruby
javascript / rust

Re: Работа с битами (использование операторов)

Сообщение Sho0ter » 13 ноя 2010, 19:54

Fedcomp писал(а):И потерял всю производительность. Правильно делается через #define, charsmax тому пример

[pawn]#define _bits_included

new bitsuser;

#define is_user_bit(%1) (bitsuser & (1 << (%1 - 1)))
#define add_user_bit(%1) (bitsuser |= (1 << (%1 - 1)))
#define remove_user_bit(%1) (bitsuser &= ~(1 << (%1 - 1)))  
[/pawn]
Хотя особой разницы не вижу.
Последний раз редактировалось Sho0ter 14 ноя 2010, 00:47, всего редактировалось 1 раз.
Аватара пользователя
Sho0ter
 
Сообщения: 585
Зарегистрирован: 31 мар 2010, 19:18
Откуда: г. Белая Церковь, Украина
Благодарил (а): 12 раз.
Поблагодарили: 307 раз.
Опыт программирования: Больше трех лет
Языки программирования: Counter-Strike 1.6
Half-Life 1

Re: Работа с битами (использование операторов)

Сообщение Fedcomp » 13 ноя 2010, 23:06

Разница в скорости. Именно ради скорости битсуммы и юзаются
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.


"я ставлю зависимости потому что мне приятно" - subb98 @ 2017
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4936
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 813 раз.
Поблагодарили: 1317 раз.
Языки программирования: =>
pawn / php / python / ruby
javascript / rust

Re: Работа с битами (использование операторов)

Сообщение KORD_12.7 » 14 ноя 2010, 05:43

[pawn]#if defined _bits_included
    #endinput
#endif
#define _bits_included
/*
    Bits manipulation Zefir<[email protected]>
        developed for Cerberus project
        http://cerberus.cstrike.in.ua/
    spring 2008 (c) Zefir

*/

/*
    bits manipulation
    predefine bit numbers as:

        enum e_flags {
            FLAG_1,
            FLAG_2,
            FLAG_3,
            FLAG_4
        }

    and use as:

        new flag
        set_bit(flag, FLAG_2)
        get_bit(flag, FLAG_3)
*/
#define set_bit(%1,%2)    (%1 |= (1<<%2))
#define get_bit(%1,%2)    (%1 & (1<<%2))
#define clr_bit(%1,%2)    (%1 &= ~(1<<%2))

/*
    bitmask manipulation
    predefine bits as:

        #define CLIENT_FLAG_1    (1<<0)
        #define CLIENT_FLAG_2    (1<<1)
        #define CLIENT_FLAG_3    (1<<2)
        #define CLIENT_FLAG_4    (1<<3)

    and use it:

        new flag[32]
        //set both flags
        set_bits(flag[1], CLIENT_FLAG_1 | CLIENT_FLAG_3)
        // clear bits
        clr_bits(flag[1], CLIENT_FLAG_1 | CLIENT_FLAG_4 | CLIENT_FLAG_2)
*/
#define set_bits(%1,%2)    (%1 |= %2)
#define get_bits(%1,%2)    (%1 & %2)
#define clr_bits(%1,%2)    (%1 &= ~%2)

/*
    big count bits manipulation
    define bits container as array
    new flags[4]
    possible 4 * 32 = 128 bit stored
    
    Big thanks ConnorMcLeod for optimization
*/
#define set_big_bit(%1,%2)    (%1[%2>>5] |= 1<<(%2 & 31))
#define get_big_bit(%1,%2)    (%1[%2>>5] & 1<<(%2 & 31))
#define clr_big_bit(%1,%2)    (%1[%2>>5] &= ~(1 << (%2 & 31)))  
[/pawn]
Вы должны зарегистрироваться, чтобы видеть ссылки.

_http://aghl.ru/ - Half-Life и Adrenaline Gamer: за пределами возможного
Аватара пользователя
KORD_12.7
Скриптер
 
Сообщения: 298
Зарегистрирован: 28 сен 2009, 10:14
Откуда: Владивосток
Благодарил (а): 142 раз.
Поблагодарили: 257 раз.
Опыт программирования: Больше трех лет
Языки программирования: Half-Life
Opposing Force
Adrenaline Gamer
Counter-Strike

Re: Работа с битами (использование операторов)

Сообщение Fedcomp » 14 ноя 2010, 11:42

разве дефайны из инклюда работают?
Не помогаю в ЛС - есть форум.
Плагины тоже не пишу, на форуме достаточно хороших скриптеров.


"я ставлю зависимости потому что мне приятно" - subb98 @ 2017
Аватара пользователя
Fedcomp
Администратор
 
Сообщения: 4936
Зарегистрирован: 28 авг 2009, 20:47
Благодарил (а): 813 раз.
Поблагодарили: 1317 раз.
Языки программирования: =>
pawn / php / python / ruby
javascript / rust

Пред.След.

Вернуться в Статьи / фрагменты кода

Кто сейчас на конференции

Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 6