2014-09-13 2 views
-1

Я работаю над методом, который должен возвращать значение поля. Пример проверки работоспособности: если поле имеет ширину три бита и без знака, результат будет иметь значение от 0 до 7, независимо от фактической позиции битов в значении. Если значение подписано, результат будет находиться между -4 и 3. Кроме того, если значение будет подписано, оно будет отрицательным только в том случае, если левый самый бит поля равен 1. В этом случае поле должно быть расширено знаком (т. е. сделать все биты влево 1). То, что я логически кажется правильным для меня, но, похоже, не работает.Метод getField в C

В моем тесте я получаю это правильно, когда это 0: somepoint; Я получаю терпит неудачу, когда это somepoint: somepoint

int getField (int value, int hi, int lo, int isSigned) { 
    int x = 0; 
    //int result = 0; 
    for(int i =lo; i < hi; i++){ 
     x |= (1 << i); 
    } 
    if(isSigned == 1){ 
     value |= ~x; 
    } 
    else{ 
     value &= x; 
    } 
    int finalresult = value >> lo; 
    return finalresult; 
} 
+2

Просьба представить пример ввода и вывода, в идеале, с помощью метода 'main()', который показывает, как использовать эту функцию. Опишите, что происходит, когда вы запускаете свой код и как он отличается от того, что вы ожидаете. –

ответ

2

Вместо

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. инвертировать все биты
  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 прыжка ...

  1. если (isSigned
  2. & & (привет = 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; 
} 

- только один прыжок.

Смежные вопросы