我正在研究一种方法,该方法假设返回字段的值。完整性检查示例:如果字段是三位宽且无符号,则结果将是介于0和7之间的值,而不管位中值的实际位置如何。如果值已签名,则结果将介于-4和3之间。此外,如果值已签名,则仅当字段的最左位为1时才为负。在这种情况下,字段必须为符号扩展(即使所有位都在左边1)。我逻辑上看起来对我来说似乎是正确的,但似乎是关闭的。
在我的测试中,当它为0时,我得到了正确的结果;当它有点时,我会失败:某点
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;
}
答案 0 :(得分:2)
而不是
int x = 0;
for(int i =lo; i < hi; i++){
x |= (1 << i);
}
你可以这样做
int x = ((1 << (hi-lo)) - 1) - ((1 << lo) -1);
或从(hi-lo)中加/减1 - 这取决于 hi 位是否为“in”。
为什么?
1 => 0000 0001
1 << 5 => 0010 0000
(1 << 5) - 1 => 0001 1111
此外,负数采用U2表示法,因此如果您想要否定数字,则需要执行两个步骤:
因此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次跳转......
在此版本中:
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;
}
只有一次跳跃。