Сдвиг битов GMP не работает на отрицательных числах

Я нашел эту функцию на php.net. Кажется, он работает на положительных числах, но не на отрицательных:

function gmp_shiftr($x,$n) { // shift right
  return(gmp_div($x,gmp_pow(2,$n)));
} 

echo -1 >> 8; //returns -1, presumably correctly
echo "<br />";
echo gmp_strval(gmp_shiftr(-1,8)); //returns 0, presumably incorrectly

Как я могу исправить функцию для работы с негативами?

У меня есть две идеи:

Может быть, я мог бы сделать что-то вроде

if (whatever) { $a >> $b} else{ gmp_shiftr($a, $b) }?

Или, может быть, я мог бы вычесть что-то из отрицательных результатов в зависимости от их стоимости..?

Я просто хочу получить значение, которое >> дал бы, но также получить его для>32-битных чисел, когда я использую GMP.

2 ответа

Глядя на документацию GMP для подпрограмм разделения, есть функция

void mpz_tdiv_q_2exp (mpz_t q, mpz_t n, unsigned long int b)

кажется, что это может быть то, что вы хотите: арифметический сдвиг вправо, который лечит n как если бы он был представлен в двух дополнениях, и (я думаю) сдвигает его b места справа. К сожалению, этот уровень API, похоже, не раскрывается PHP GMP.

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

unsigned b; // number of bits representing the number in x
int x;      // sign extend this b-bit number to r
int r;      // resulting sign-extended number
int const m = 1U << (b - 1); // mask can be pre-computed if b is fixed

x = x & ((1U << b) - 1);  // (Skip this if bits in x above position b are already zero.)
r = (x ^ m) - m;

Поскольку побитовое AND и XOR поддерживаются PHP GMP, вы можете сделать это...

Если вы думаете об этом математически, это имеет смысл. gmp_shiftr выполняет -1/256, что при округлении до нуля (по умолчанию gmp) равно 0.

Метод ">>" работает так же, как и он, потому что отрицательные числа представлены в виде дополненного двойным знаком дополнения.

Другие вопросы по тегам