В качестве упражнения я должен написать следующую функцию:
умножить x на 2, насыщать до Tmin / Tmax при переполнении, используя только побитовые и битовые операции сдвига.
Теперь это мой код:
// xor MSB and 2nd MSB. if diferent, we have an overflow and SHOULD get 0xFFFFFFFF. otherwise we get 0.
int overflowmask = ((x & 0x80000000) ^ ((x & 0x40000000)<<1)) >>31;
// ^ this arithmetic bit shift seems to be wrong
// this gets you Tmin if x < 0 or Tmax if x >= 0
int overflowreplace = ((x>>31)^0x7FFFFFFF);
// if overflow, return x*2, otherwise overflowreplace
return ((x<<1) & ~overflowmask)|(overflowreplace & overflowmask);
теперь, когда overflowmask
должно быть 0xFFFFFFFF
, вместо этого оно равно 1, что означает, что арифметическое c битовое смещение >>31
сместилось в 0 с вместо 1 с (MSB получил XORed к 1 , затем смещено вниз).
x подписано и MSB равно 1, поэтому согласно C99 арифметическое c смещение вправо должно заполняться 1 с. Чего мне не хватает?
РЕДАКТИРОВАТЬ: Я только что догадался, что этот код не является правильным. Чтобы обнаружить переполнение, достаточно, чтобы 2-й MSB был равен 1.
Однако мне все еще интересно, почему сдвиг битов заполняется 0 с.
РЕДАКТИРОВАТЬ:
Пример: x = 0xA0000000
x & 0x80000000 = 0x80000000
x & 0x40000000 = 0
XOR => 0x80000000
>>31 => 0x00000001
РЕДАКТИРОВАТЬ:
Решение:
int msb = x & 0x80000000;
int msb2 = (x & 0x40000000) <<1;
int overflowmask = (msb2 | (msb^msb2)) >>31;
int overflowreplace = (x >>31) ^ 0x7FFFFFFF;
return ((x<<1) & ~overflowmask) | (overflowreplace & overflowmask);