Побитовые операции

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
Добрый день
Имеется такой код:
C-подобный:
bool g_iTest;

public void OnPluginStart()
{
   RegConsoleCmd("sm_test", ConCmd_Test);
}

public Action ConCmd_Test(int iClient, int iArgc)
{
   // bool variable has 8 bit = 1 byte
   //bool iCampCount = g_iTest & 0xF;    // NOTE: First 4 bit (0xF = hexadecimal number systeam)
   bool iCampValue = g_iTest >> 4;        // NOTE: Second 4 bit

   PrintToChatAll("iCampCount: %i | iCampValue: %i", g_iTest & 0xF, iCampValue);

   iCampValue++;
   g_iTest = ++g_iTest & 0xF | iCampValue << 4;

   return Plugin_Handled;
}
Как мне в g_iTest (смещенном на 4 бита влево) получить число 2, 3, 4, и так далее, не используя переменную
C-подобный:
iCampValue
Как я это сделал с g_iTest & 0xF
P.S. С побитовыми операциями еще мало знаком, не пинайте в случае чего
 

RudikS

Участник
Сообщения
130
Реакции
61
Добрый день
Имеется такой код:
C-подобный:
bool g_iTest;

public void OnPluginStart()
{
   RegConsoleCmd("sm_test", ConCmd_Test);
}

public Action ConCmd_Test(int iClient, int iArgc)
{
   // bool variable has 8 bit = 1 byte
   //bool iCampCount = g_iTest & 0xF;    // NOTE: First 4 bit (0xF = hexadecimal number systeam)
   bool iCampValue = g_iTest >> 4;        // NOTE: Second 4 bit

   PrintToChatAll("iCampCount: %i | iCampValue: %i", g_iTest & 0xF, iCampValue);

   iCampValue++;
   g_iTest = ++g_iTest & 0xF | iCampValue << 4;

   return Plugin_Handled;
}
Как мне в g_iTest (смещенном на 4 бита влево) получить число 2, 3, 4, и так далее, не используя переменную
C-подобный:
iCampValue
Как я это сделал с g_iTest & 0xF
P.S. С побитовыми операциями еще мало знаком, не пинайте в случае чего
Если правильно понял, то примерно так
C-подобный:
 g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10;
 

RudikS

Участник
Сообщения
130
Реакции
61
Не работает, обе части из 4 бит всегда равны ноль
Может я задачу не понял. Я понял как прибавить единицу к обоим частям байта.
1619933194069.png
1619933208242.png
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
Если правильно понял, то примерно так
Используй Силу скобочки Люк! (с)
Сообщения автоматически склеены:

@Vit_ amin, тебе нужно передать через аргумент в виде int (т.е. 4-байтное число) 4 числа по байту (0 - 127)?
Или цель другая?
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
Может я задачу не понял. Я понял как прибавить единицу к обоим частям байта.
Посмотреть вложение 77055Посмотреть вложение 77056
Я имел в виду:
  • Необходимо извлечь из левой и правой части по 4 бита
  • *** Тут моя функция, где я с этими значениями что-то делаю ***
  • Сделать операцию инкремента для левой и правой части по 4 бита
  • Занести всё это в ту же переменную
C-подобный:
   PrintToServer("Right shifted: %i | Left Shifted: %i", g_iTest & 0xF, g_iTest & 0xF0);
   PrintToServer("g_iTest: %i", g_iTest);
   g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10;
C-подобный:
] sm_test
Right shifted: 1 | Left Shifted: 16
g_iTest: 17
] sm_test
Right shifted: 2 | Left Shifted: 32
g_iTest: 34
@Grey83: Обяъснил
Сообщения автоматически склеены:

@RudikS Все, сори, моя ошибка (работает):
C-подобный:
char g_iTest;

public void OnPluginStart()
{
   RegConsoleCmd("sm_test", ConCmd_Test);
}

public Action ConCmd_Test(int iClient, int iArgc)
{
   // NOTE: 0000 0000 = 1 byte (8 bit)
   // NOTE: 1111 1111 = 255 - Decimal number systeam
   // NOTE: char preventing warning 213 in compile process
   PrintToServer("Right shifted: %i | Left Shifted: %i", g_iTest & 0xF, g_iTest >> 4);
   PrintToServer("g_iTest: %i", g_iTest);
   g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10;

   return Plugin_Handled;
}
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
Необходимо извлечь из левой и правой части по 4 бита
значит максимальное число в каждой части равно 15

разделение 32-битного числа на 8шт 4-битных:
C-подобный:
public void OnPluginStart()
{
    RegConsoleCmd("sm_test", Cmd_Test);
}

public Action Cmd_Test(int client, int argc)
{
    if(!argc)
    {
        ReplyToCommand(client, "You should input any number!");
        return Plugin_Handled;
    }

    char buffer[12];
    GetCmdArg(1, buffer, sizeof(buffer));
    int value = StringToInt(buffer);
    ReplyToCommand(client, "Value: %i", value);
    for(int i, offset = 0xF, val; i < 8; i++)
    {
        if(i)
        {
            val = 4 * i;
            offset = 0xF << val;
            ReplyToCommand(client, "%i) %2i <== (%i & 0x%x) >> %i", i, (value & offset) >> val, value, offset, val);
        }
        else ReplyToCommand(client, "%i) %2i <==  %i & 0x%x", i, value & offset, value, offset);
    }

    return Plugin_Handled;
}
Вот результат работы:
C-подобный:
sm_test 15
Value: 15
0) 15 <==  15 & 0xf
1)  0 <== (15 & 0xf0) >> 4
2)  0 <== (15 & 0xf00) >> 8
3)  0 <== (15 & 0xf000) >> 12
4)  0 <== (15 & 0xf0000) >> 16
5)  0 <== (15 & 0xf00000) >> 20
6)  0 <== (15 & 0xf000000) >> 24
7)  0 <== (15 & 0xf0000000) >> 28

sm_test 16
Value: 16
0)  0 <==  16 & 0xf
1)  1 <== (16 & 0xf0) >> 4
2)  0 <== (16 & 0xf00) >> 8
3)  0 <== (16 & 0xf000) >> 12
4)  0 <== (16 & 0xf0000) >> 16
5)  0 <== (16 & 0xf00000) >> 20
6)  0 <== (16 & 0xf000000) >> 24
7)  0 <== (16 & 0xf0000000) >> 28

sm_test 2000000000
Value: 2000000000
0)  0 <==  2000000000 & 0xf
1)  0 <== (2000000000 & 0xf0) >> 4
2)  4 <== (2000000000 & 0xf00) >> 8
3)  9 <== (2000000000 & 0xf000) >> 12
4)  5 <== (2000000000 & 0xf0000) >> 16
5)  3 <== (2000000000 & 0xf00000) >> 20
6)  7 <== (2000000000 & 0xf000000) >> 24
7)  7 <== (2000000000 & 0xf0000000) >> 28
Сообщения автоматически склеены:

Сделать операцию инкремента для левой и правой части по 4 бита
Инкремент - это просто увеличение значения
Тебе же сложение нужно, а не инкремент?
 
Последнее редактирование:

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
значит максимальное число в каждой части равно 15

разделение 32-битного числа на 8шт 4-битных:
C-подобный:
public void OnPluginStart()
{
    RegConsoleCmd("sm_test", Cmd_Test);
}

public Action Cmd_Test(int client, int argc)
{
    if(!argc)
    {
        ReplyToCommand(client, "You should input any number!");
        return Plugin_Handled;
    }

    char buffer[12];
    GetCmdArg(1, buffer, sizeof(buffer));
    int value = StringToInt(buffer);
    ReplyToCommand(client, "Value: %i", value);
    for(int i, offset = 0xF, val; i < 8; i++)
    {
        if(i)
        {
            val = 4 * i;
            offset = 0xF << val;
            ReplyToCommand(client, "%i) %2i <== (%i & 0x%x) >> %i", i, (value & offset) >> val, value, offset, val);
        }
        else ReplyToCommand(client, "%i) %2i <==  %i & 0x%x", i, value & offset, value, offset);
    }

    return Plugin_Handled;
}
Вот результат работы:
C-подобный:
sm_test 15
Value: 15
0) 15 <==  15 & 0xf
1)  0 <== (15 & 0xf0) >> 4
2)  0 <== (15 & 0xf00) >> 8
3)  0 <== (15 & 0xf000) >> 12
4)  0 <== (15 & 0xf0000) >> 16
5)  0 <== (15 & 0xf00000) >> 20
6)  0 <== (15 & 0xf000000) >> 24
7)  0 <== (15 & 0xf0000000) >> 28

sm_test 16
Value: 16
0)  0 <==  16 & 0xf
1)  1 <== (16 & 0xf0) >> 4
2)  0 <== (16 & 0xf00) >> 8
3)  0 <== (16 & 0xf000) >> 12
4)  0 <== (16 & 0xf0000) >> 16
5)  0 <== (16 & 0xf00000) >> 20
6)  0 <== (16 & 0xf000000) >> 24
7)  0 <== (16 & 0xf0000000) >> 28

sm_test 2000000000
Value: 2000000000
0)  0 <==  2000000000 & 0xf
1)  0 <== (2000000000 & 0xf0) >> 4
2)  4 <== (2000000000 & 0xf00) >> 8
3)  9 <== (2000000000 & 0xf000) >> 12
4)  5 <== (2000000000 & 0xf0000) >> 16
5)  3 <== (2000000000 & 0xf00000) >> 20
6)  7 <== (2000000000 & 0xf000000) >> 24
7)  7 <== (2000000000 & 0xf0000000) >> 28
Сообщения автоматически склеены:


Инкремент - это просто увеличение значения
Тебе же сложение нужно, а не инкремент?
Ну получается да, нужно сложение в побитовом варианте
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
Побитовое сложение?
Вот это, что ли? 10 | 7 (1010 | 0111) = 15 (1111)
Сообщения автоматически склеены:

Код, который я скинул в сообщение от @RudikS работает, имеется в виду это то, что мне необходимо было
@Grey83 P.S. Спасибо за код выше
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
Код, который я скинул в сообщение от @RudikS работает, имеется в виду это то, что мне необходимо было
g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10; - это g_iTest = g_iTest + 1 | (g_iTest & 0xF0) + 16;
g_iTest & 0xF0
оставляет от числа только 4 бита с 8-го по 5-й (т.е. числа с 16 до 240, с разницей в 16)
В общем какая-то фигня получается в результате
Почему просто не прибавлять 17? =)
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10; - это g_iTest = g_iTest + 1 | (g_iTest & 0xF0) + 16;
g_iTest & 0xF0
оставляет от числа только 4 бита с 8-го по 5-й (т.е. числа с 16 до 240, с разницей в 16)
В общем какая-то фигня получается в результате
Почему просто не прибавлять 17? =)
Ну, твой код выводит следующее:
C-подобный:
] sm_test
Right shifted: 0 | Left Shifted: 0
g_iTest: 0
] sm_test
Right shifted: 1 | Left Shifted: 1
g_iTest: 17
] sm_test
Right shifted: 2 | Left Shifted: 3
g_iTest: 50
] sm_test
Right shifted: 3 | Left Shifted: 7
g_iTest: 115
] sm_test
Right shifted: 4 | Left Shifted: 15
g_iTest: 244

C-подобный:
   PrintToServer("Right shifted: %i | Left Shifted: %i", g_iTest & 0xF, g_iTest >> 4);
   PrintToServer("g_iTest: %i", g_iTest);

   g_iTest = g_iTest + 1 | (g_iTest & 0xF0) + 16

50 в десятичной это получает 0011 0010 в двоичной (я про сумму g_iTest)
Сообщения автоматически склеены:

@RudikS Я же правильно понимаю смысл того, что ты описал мне:
C-подобный:
   g_iTest = g_iTest + 1 & 0xF | g_iTest & 0xF0;
   // RIGHT SIDE
   // 0000 0000 (g_iTest) (right side)
   // +
   // 0000 0001 (1)
   // +
   // 0000 1111 (& 0xF) - hexadecimal system number
   // =
   // 0000 0001

   // LEFT SIDE
   // 0000 0000 (g_iTest) (left side)
   // +
   // 1111 0000 (& 0xF0) - hexadecimal system number
   // =
   // 0000 0000

   // BITWISE OR
   // 0000 0001
   // 0000 0000
   // =
   // 0000 0001
 
Последнее редактирование:

RudikS

Участник
Сообщения
130
Реакции
61
Ну, твой код выводит следующее:
C-подобный:
] sm_test
Right shifted: 0 | Left Shifted: 0
g_iTest: 0
] sm_test
Right shifted: 1 | Left Shifted: 1
g_iTest: 17
] sm_test
Right shifted: 2 | Left Shifted: 3
g_iTest: 50
] sm_test
Right shifted: 3 | Left Shifted: 7
g_iTest: 115
] sm_test
Right shifted: 4 | Left Shifted: 15
g_iTest: 244

C-подобный:
   PrintToServer("Right shifted: %i | Left Shifted: %i", g_iTest & 0xF, g_iTest >> 4);
   PrintToServer("g_iTest: %i", g_iTest);

   g_iTest = g_iTest + 1 | (g_iTest & 0xF0) + 16

50 в десятичной это получает 0011 0010 в двоичной (я про сумму g_iTest)
Сообщения автоматически склеены:

@RudikS Я же правильно понимаю смысл того, что ты описал мне:
C-подобный:
   g_iTest = g_iTest + 1 & 0xF | g_iTest & 0xF0;
   // RIGHT SIDE
   // 0000 0000 (g_iTest) (right side)
   // +
   // 0000 0001 (1)
   // +
   // 0000 1111 (& 0xF) - hexadecimal system number
   // =
   // 0000 0001

   // LEFT SIDE
   // 0000 0000 (g_iTest) (left side)
   // +
   // 1111 0000 (& 0xF0) - hexadecimal system number
   // =
   // 0000 0000

   // BITWISE OR
   // 0000 0001
   // 0000 0000
   // =
   // 0000 0001
В целом правильно, но побитовое & это *, а не +. И с приоритетом операций аккуратней будь.
g_iTest = g_iTest + 1 & 0xF | (g_iTest & 0xF0) + 0x10; - это g_iTest = g_iTest + 1 | (g_iTest & 0xF0) + 16;
g_iTest & 0xF0
оставляет от числа только 4 бита с 8-го по 5-й (т.е. числа с 16 до 240, с разницей в 16)
В общем какая-то фигня получается в результате
Почему просто не прибавлять 17? =)
Он хочет разделять на правую и левую часть. Обрабатывать как-то эти значения и только потом соединять с дальнейшим сложением с единицей каждой части я так понимаю.
 

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
@RudikS, так вот я и не понимаю что он в результате хочет получить.


Я же давал тебе ссыль на википедию. Почитай там про битовые операции
1 & 0xF это битовое И, т.е. в результате те биты, которые были равны 1 в обоих числах, останутся, а которые были равны 1 только в одном из чисел станут 0
И ещё приоритет выше у битовых операций, потом у умножения/деления и уже после у сложения/вычитания (это на вики АМ можно почитать, емнип).
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
@RudikS, так вот я и не понимаю что он в результате хочет получить.


Я же давал тебе ссыль на википедию. Почитай там про битовые операции
1 & 0xF это битовое И, т.е. в результате те биты, которые были равны 1 в обоих числах, останутся, а которые были равны 1 только в одном из чисел станут 0
И ещё приоритет выше у битовых операций, потом у умножения/деления и уже после у сложения/вычитания (это на вики АМ можно почитать, емнип).
Ок, спасибо, буду изучать тогда
Сообщения автоматически склеены:

@Grey83 @RudikS Это же получается то же самое:
C-подобный:
   // 0000 0000
   // 1111 1111 = 255 - Decimal number systeam
   // char variable has 8 bit = 1 byte
   PrintToServer("Right shifted: %i | Left Shifted: %i", g_iTest & 0xF, g_iTest >> 4);
   PrintToServer("g_iTest: %i", g_iTest);

   g_iTest += 0x11;

C-подобный:
Right shifted: 0 | Left Shifted: 0
g_iTest: 0
] sm_test
Right shifted: 1 | Left Shifted: 1
g_iTest: 17
] sm_test
Right shifted: 2 | Left Shifted: 2
g_iTest: 34
] sm_test
Right shifted: 3 | Left Shifted: 3
g_iTest: 51
] sm_test
Right shifted: 4 | Left Shifted: 4
g_iTest: 68
] sm_test
Right shifted: 5 | Left Shifted: 5
g_iTest: 85
] sm_test
Right shifted: 6 | Left Shifted: 6
g_iTest: 102
 
Последнее редактирование:

Grey83

не пишу плагины с весны 2022
Сообщения
8,520
Реакции
4,979
@Vit_ amin, только ещё учитывай то, что при переполнении (когда сложишь 16 раз) старший разряд правой части числа перейдёт в младший разряд левой части.
Так что простым сложением не обойтись, если нужно исправить эту проблему.
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
@Vit_ amin, только ещё учитывай то, что при переполнении (когда сложишь 16 раз) старший разряд правой части числа перейдёт в младший разряд левой части.
Так что простым сложением не обойтись, если нужно исправить эту проблему.
@Grey83 В том то и суть, я хочу съэкономить на оперативной памяти (понятное дело, что это всегло-лишь какие то килобайты памяти, но тут суть воспроса в другом) и использовать по максимуму тот же char или bool, так как мне как раз таки в данном случае не нужно хранить числа больше 15, поэтому не хочу создавать две глобальные переменные типа int и хранить числа, которые не превышают даже 10 (для моих целей)
К тому же побитовые операции производят оптимизацию вычислений в обход компилятора
P.S. Подправьте, если в чём то не прав разумеется
 

RudikS

Участник
Сообщения
130
Реакции
61
@Grey83 В том то и суть, я хочу съэкономить на оперативной памяти (понятное дело, что это всегло-лишь какие то килобайты памяти, но тут суть воспроса в другом) и использовать по максимуму тот же char или bool, так как мне как раз таки в данном случае не нужно хранить числа больше 15, поэтому не хочу создавать две глобальные переменные типа int и хранить числа, которые не превышают даже 10 (для моих целей)
К тому же побитовые операции производят оптимизацию вычислений в обход компилятора
P.S. Подправьте, если в чём то не прав разумеется
Ты будешь делать на 1 команду больше для чтения (сдвиг для левой части и умножение побитовое для правой части). Если уж настолько подходить серьезно к оптимизации, то нужно решать, что будет чаще происходить чтение или запись этих чисел. Запись, если не ошибаюсь, компилятор сумеет за счет константы к 1 команде свести. Возможно отдать пару байт было бы выгоднее.
 

Vit_ amin

Добрая душа
Сообщения
1,504
Реакции
660
Ты будешь делать на 1 команду больше для чтения (сдвиг для левой части и умножение побитовое для правой части). Если уж настолько подходить серьезно к оптимизации, то нужно решать, что будет чаще происходить чтение или запись этих чисел. Запись, если не ошибаюсь, компилятор сумеет за счет константы к 1 команде свести. Возможно отдать пару байт было бы выгоднее.
Ну я понимаю это, поэтому вместо того, чтобы создавать две глобальные переменные, есть смысл создать две локальные переменные, которые будут извлекать 4 бита из каждой части, потом что-то делать с ними и уже потом записывать их в глобаную одну переменную
Просто если взять char это 1 байт, а если взять int это уже 4 байта и можно большие числа записывать или просто в одну переменную можно записать больше чисел побитово, я не скажу, что это везде удобно и применимо, но в некоторых случаях почему бы и нет
Сообщения автоматически склеены:

Конечно идеально наверное посмотреть машинный код всех этих операции или простым benchmark
 
Сверху Снизу