Вместо
int x = 0;
for(int i =lo; i < hi; i++){
x |= (1 << i);
}
вы можете сделать, как
int x = ((1 << (hi-lo)) - 1) - ((1 << lo) -1);
или добавить/вычесть дополнительный 1 из (Hi-Lo) - это зависит если привет бит «в» или нет.
Почему?
1 => 0000 0001
1 << 5 => 0010 0000
(1 << 5) - 1 => 0001 1111
Кроме того, отрицательные числа в U2 записи, так что если вы хотите, чтобы свести на нет количество вам нужно сделать 2 шага:
- инвертировать все биты
- добавить 1
НИХ value |= ~x
не достаточно (вы будете инвертировать нули, но не остальное, и вам все равно придется добавить 1). Вы можете просто инвертировать с value ^= (-1)
. Вот почему случай somepoint: somepoint не работал.
я написал что-то вроде этого:
#include <cassert>
int getField(int value, int hi, int lo, int isSigned) {
int result = 0;
assert(hi >= lo);
// let say we are interested in folowing bits:
// (marked as 1)
// value := 0001 1100
// so:
// hi := 5
// lo := 2
// and e.g.:
// isSigned := 1
isSigned = (value >> (hi-1)) & isSigned; // isSigned will be 1 if (it was
// 1 and proper bit is set to 1)
// ((0001 1100) >> 4) & 1
// 0000 0001 & 1
// 0000 0001
// isSigned := 1
value >>= lo; // move interested bits that they start at 0
// ((0001 1100) >> 2
// 0000 0111
// value := 0000 0111
hi -= lo; // how many bits we want?
// hi := 3
isSigned &= (hi != 0); // hi == 0 <=> hi == lo
// => sign will be always 0
// 1 &= (3 != 0)
// 1
// isSigned := 1
hi -= isSigned; // if the last bit should be sign-bit
// don't evaluate it as value
// hi := 2
result = value & ((1 << hi) - 1); // (1<<hi)-1 creates bit mask
// 0000 0111 & ((1 << 2) - 1)
// 0000 0111 & (100 - 1)
// 0000 0111 & 011
// 0000 0011
// result := 3
if (isSigned) // true
return -result; // return inverted result
// -3
return result; // if false return result
}
int main()
{
assert(0 == getField(0, 0, 0, 0));
assert(0 == getField(0, 0, 0, 1));
assert(0 == getField(15, 0, 0, 0));
assert(0 == getField(15, 0, 0, 1));
assert(0 == getField(15, 1, 1, 0));
assert(0 == getField(15, 3, 3, 1));
assert(0 == getField(0, 3, 0, 0));
assert(0 == getField(0, 4, 0, 1));
// (sign bit)[value bits]
assert(1 == getField(1, 1, 0, 0)); // 000[1]
assert(0 == getField(1, 1, 0, 1)); // 000(1)
assert(3 == getField(15, 2, 0, 0)); // 11[11]
assert(1 == getField(15, 2, 1, 0)); // 11[1]1
assert(7 == getField(15, 4, 1, 0)); // [111]1
assert(2 == getField(5, 4, 1, 0)); // [010]1
assert(2 == getField(5, 3, 1, 0)); // 0[10]1
assert(5 == getField(10, 4, 1, 0)); // [101]0
assert(1 == getField(10, 3, 1, 0)); // 1[01]0
assert(-1 == getField(15, 2, 0, 1)); // 11(1)[1]
assert(0 == getField(15, 2, 1, 1)); // 11(1)1
assert(-3 == getField(15, 4, 1, 1)); // (1)[11]1
assert(2 == getField(5, 4, 1, 1)); // (0)[10]1
assert(0 == getField(5, 3, 1, 1)); // 0(1)[0]1
assert(-1 == getField(10, 4, 1, 1)); // (1)[01]0
assert(1 == getField(10, 3, 1, 1)); // 1(0)[1]0
assert(-2 == getField(12, 4, 1, 1)); // (1)[10]0
assert(-2 == getField(10, 4, 0, 1)); // (1)[010]
assert(-3 == getField(28, 5, 2, 1)); // 000(1) [11]00
}
Там нет петли. 2 прыжка ((hi != 0)
и if(isSigned)
), но для меня VCv120 в режиме выпуска как-то обрабатывает первый, поэтому в коде я получаю только if()
. Я не уверен, как избавиться от него.
Также нет умножения (<<
- сдвиг битов вместо времен умножения 2) и всего 4 вычитания. Не знаете, что один будет быстрее ... Это один оставшийся прыжок ...
Еще одна функция времени (на этот раз без комментариев)
int getField(int value, int hi, int lo, int isSigned) {
int result = 0;
assert(hi >= lo);
isSigned = (value >> (hi-1)) & isSigned;
value >>= lo;
hi -= lo;
isSigned &= (hi != 0);
hi -= isSigned;
result = value & ((1 << hi) - 1);
if (isSigned)
return -result;
return result;
}
Редактировать
Я успел немного очистки код:
int getField(int value, int hi, int lo, int isSigned) {
assert(hi >= lo);
hi -= lo;
value >>= lo;
value &= ((1 << hi) - 1);
isSigned <<= (hi - 1);
isSigned &= value;
if (isSigned && (hi != 0)) {
value -= isSigned;
value = ~value + 1;
}
return value;
}
, но сгенерированный asm имеет 2 прыжка ...
- если (isSigned
- & & (привет = 0)!)
Edit 2
В этой версии:
int getField(int value, int hi, int lo, int isSigned) {
assert(hi >= lo);
hi -= lo;
isSigned &= (hi != 0);
value >>= lo;
value &= ((1 << hi) - 1);
isSigned <<= (hi - 1);
isSigned &= value;
if (isSigned) {
value -= isSigned;
value = ~value + 1;
}
return value;
}
- только один прыжок.
Просьба представить пример ввода и вывода, в идеале, с помощью метода 'main()', который показывает, как использовать эту функцию. Опишите, что происходит, когда вы запускаете свой код и как он отличается от того, что вы ожидаете. –