Как использовать битовый флаг в беззнаковом int для хранения в нем дополнительного значения bool - PullRequest
2 голосов
/ 07 ноября 2011

Я использую целые числа без знака, представляющие кучу самолетов в игре. Каждый самолет имеет два состояния, летящее и заземленное. Я хотел бы сохранить это состояние вместе с номером самолета. Каков «лучший» способ достичь этого? Я мог бы использовать std :: maps с плоскостями и их состоянием, но это кажется излишним и медленным. Можно ли это сделать с помощью битовых флагов? Назначение и тестирование теста должны быть быстрыми.

Псевдокод:

unsigned int Boing = 777;

if( Boing is flying)
 set some bit;

is Boing flying? (how to check for the current state)

Любая подсказка о простой и быстрой технике приветствуется!

Ответы [ 9 ]

2 голосов
/ 07 ноября 2011

Одним простым способом было бы просто сделать число отрицательным, если не летать.

2 голосов
/ 07 ноября 2011
struct Stuff
{
  unsigned int Boing: 31;
  unsigned int isFlying: 1;
};

.
.
.

Stuff myStuff;
myStuff.Boing = 777;
myStuff.isFlying = false;

Подробнее о битовых полях

2 голосов
/ 07 ноября 2011

Самый быстрый и чистый способ, вероятно, состоит в том, чтобы избежать битовых полей и просто определить структуру:

struct Plane
{
    bool isFlying;
    unsigned int number;
}

...


std::vector<Plane> planes;
Plane p;
p.isFlying = true;
p.number = 777;
planes.push_back(p);

Этот метод будет использовать больше памяти, чем пытаться втиснуть флаг в одно и то же слово, но займет меньшеработать, чтобы получить / установить поля.Если вы не ограничены в памяти, я бы настоятельно рекомендовал не пытаться все упаковать плотно.

Можно даже рассмотреть возможность использования enum вместо bool для состояния.

1 голос
/ 07 ноября 2011

Почему бы просто не подписать свои целые числа? Положительные значения летят, отрицательные нет, и ноль недействителен.

1 голос
/ 07 ноября 2011

Предполагая, что вы никогда не используете полный диапазон значений, доступных в вашем unsigned int (разумная возможность, но далеко не абсолютно точная), вы можете просто ограничить диапазон одним битом, который меньше unsigned in, и затем использовать наиболеезначительный бит для хранения «летающего» состояния.В этом случае вы можете сделать что-то вроде:

// This theoretically isn't required to work, but will for most reasonable machines.
unsigned flying_bit = 1 << (CHAR_BITS * sizeof(unsigned));

void take_off(unsigned &plane) {
    plane |= flying_bit;
}

void land(unsigned &plane) { 
    plane &= flying_bit;
}

bool is_flying(unsigned const &plane) { 
    return plane & flying_bit != 0;
}

Другой возможностью будет использование реальных битовых полей:

struct plane { 
    uint32_t model: 31;
    uint32_t flying: 1;
};

В этом случае вы просто присваиваете значения напрямую, например:

plane myplane = {777, 0};

myplane.flying = 1; // take off

myplane.flying = 0; // land
0 голосов
/ 08 ноября 2011

Как насчет набора битов, который использует в качестве номера плоскости индекс набора битов?Если вам не нужно больше состояний, то все готово.Если вам нужно, вы также можете использовать для каждого состояния (например, сбой, для восстановления требовался отдельный битовый вектор, поэтому вы используете ровно один бит для каждого состояния плоскости, в котором вы действительно нуждаетесь.

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

#include <iostream>
#include <boost/dynamic_bitset.hpp>

using namespace boost;

class State
{
public:
    State(int nPlanes):_States(dynamic_bitset<>(nPlanes))
    {
    }

    void SetState(int nPlane, bool bFly)
    {
        _States[nPlane] = bFly;
    }

    void Dump()
    {
        for (boost::dynamic_bitset<>::size_type i = 0; i < _States.size(); ++i)
            std::cout << _States[i];
    }

private:
    dynamic_bitset<> _States;
};


int _tmain(int argc, _TCHAR* argv[])
{
    State planes(500);
    planes.SetState(0, true);
    planes.SetState(5,true);
    planes.Dump();

    return 0;
}
0 голосов
/ 07 ноября 2011

Вы можете упаковать как штат, так и номер самолета в unsigned int .Предполагая, что unsigned int на вашей платформе 32-битный

unsigned int myplane;
int planenumber = (myplane & 0xffff ) //can be the plane number
int booleanstate = ((myplane >> 16) & 0xffff) //can be the boolean state
0 голосов
/ 07 ноября 2011

Допустим, у вашего беззнакового целого 32 бита:

#define SET_FLYING(x)     (x) |= (1<<31)
#define SET_GROUNDED(x)   (x) &= ~(1<<31)
#define IS_FLYING(x)      ((x) & (1<<31))
#define ID(x)             ((x) & ~(1<<31))

Если вы хотите быть более стильным в c ++, вы можете написать их как встроенные функции. Во всяком случае, я написал больше, чтобы показать вам, как выполняется битовая манипуляция, а не реализовывать ее как макрос или как функцию.

Чтобы заставить его работать с различными размерами int, вы можете изменить 31 на:

instead of 31: ((sizeof(x)<<3)-1)

Что в основном sizeof(x)*8-1

P.S. Если кто-то хочет сказать мне: «Нет, нет! Не используйте макросы, это C ++, используйте эту чрезмерно сложную вещь, которую я написал», сохраните свое дыхание. Просто дайте -1 и идите дальше.

edit : То, что я написал выше, было ответом на ваш вопрос: «Как использовать знаковый бит в качестве флага». Если вы хотите сделать это лучше, но не увеличивайте использование памяти (добавив bool), вы всегда можете написать что-то вроде этого:

struct airplane
{
    unsigned int id: 31;
    unsigned int is_flying: 1;
};

airplane Boing = {777, false};

Затем, присвоение и чтение из id или is_flying выполняет битовые операции, но они обрабатываются компилятором.

0 голосов
/ 07 ноября 2011

Используйте структуру или класс, чтобы объединить информацию "число" и "состояние" и все, что вы хотите, чтобы плоскость была. Если вы используете битовые операции над int (что возможно, но не рекомендуется), изменение состояния изменит фактическое число вашей плоскости.

...