2016-03-07 7 views
0

Как преобразовать заданный битсет длины N (где 0 < N < 64) в подписанный int. Например, учитывая:Подписанный int from bitset <n>

std::bitset<13> b("1111111101100"); 

Я хотел бы получить обратно значение -20, а не 8172.

Мой подход:

int t = (static_cast<int>(b.to_ullong())); 
if(t > pow(2, 13)/2) 
    t -= pow(2, 13); 

Есть более общий способ приблизиться к этому?

Редактировать: Также битсет на самом деле std::bitset<64>, а N может быть известным значением времени выполнения, переданным другими способами.

+0

И работает ли он так, как планировалось? –

+0

Это так, но, как вы можете видеть, не совсем ясно, что он делает. Таким образом, мой вопрос на самом деле, есть ли «более чистый» способ сделать это? – carobnodrvo

+1

Подписанный int содержит в большинстве реализаций меньше бит информации, чем битсет длиной 64, поэтому ваше преобразование должно быть потеряно. –

ответ

1

Мы можем написать шаблон функции, чтобы сделать это для нас:

template <size_t N, class = std::enable_if_t<(N > 0 && N < 64)> 
int64_t as_signed(const std::bitset<N>& b) 
{ 
    int64_t v = b.to_ullong(); // safe since we know N < 64 
    return b[N-1] ? ((1LL << N) - v) : v; 
} 
+0

Shia LaBeouf - это то, что вы :). Это не сработает. Counterexample: 'std :: bitset <63> bs (std :: string (" 1111111101100 "));' (13-разрядный номер подписки) будет 8172 вместо -20. – carobnodrvo

+0

@carobnodrvo Не понимал, что это было то, что вы хотели, отредактировал это в свой вопрос и изменил мой ответ. – Barry

0

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

struct S { int64_t x:N; } s; 
int64_t result = s.x = b.to_ullong(); 

Компилятор вероятно оптимизирует, что s вне.

Это должно быть безопасно, поскольку int64_t (если имеется) требуется для дополнения к двум.

Edit: Когда фактический подсчет битов для расширения известно лишь во время выполнения, то самый портативный алгоритм с маской:

// Do this if bits above position N in b may be are not zero to clear those. 
int64_t x = b.to_ullong() & ((1ULL << N) - 1); 
// Otherwise just 
int64_t x = b.to_ullong(); 

int64_t const mask = 1ULL << (N - 1); 
int64_t result = (x^mask) - mask; 

немного быстрее, но менее портативный метод с динамическими битовыми отсчетов с битом сдвиги (работы, когда архитектура подписала арифметический сдвиг вправо):

int const shift = 64 - N; 
int64_t result = ((int64_t)b.to_ullong() << shift) >> shift; 
+0

Но 'N' известно только во время выполнения. – carobnodrvo

+0

Если N известно только во время выполнения, тогда 'std :: bitset ' не компилируется, поэтому ваша проблема находится в другом месте. –

+0

Да, поэтому я установил N равным 64, чтобы он охватывал все возможные случаи. – carobnodrvo