【问题标题】:GMP Bit shift doesn't work on negative numbersGMP 位移不适用于负数
【发布时间】:2011-01-26 00:31:32
【问题描述】:

我在 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) }?

或者,也许我可以根据它们的价值从负面结果中减去一些东西..?

我只想获得 >> 会给出的值,但在我使用 GMP 时也获得 >32 位数字。

【问题讨论】:

    标签: php bit-manipulation bitwise-operators gmp


    【解决方案1】:

    GMP documentation for the division routines,有函数

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

    这似乎是你想要的:一个算术右移,它处理 n 好像它以二进制补码表示,并且(我认为)将它转移到 b 位置 向右。不幸的是,PHP GMP 似乎没有公开该级别的 API。

    我找到了一个bit twiddling hack 用于在位数增加时进行符号扩展 在表示中是未知的:

    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;
    

    由于 PHP GMP 支持按位 AND 和 XOR ,您也许可以使 这项工作...

    【讨论】:

      【解决方案2】:

      如果您从数学上考虑这一点,那是有道理的。 gmp_shiftr 正在执行 -1/256,当向零舍入时(gmp 默认值)为 0。

      “>>”方法的工作原理与此类似,因为负数以符号扩展的二进制补码形式表示。

      【讨论】:

      • 我也是这么想的。然后我测试了它。
      • 啊,我明白了,在某些情况下这是错误的。已更新答案以删除不正确的陈述。
      • 那么我应该怎么做才能让它像我在做一样>>?请注意,我必须在此循环中使用 GMP,因为它处理一些超出 32 位的大#s
      • 也许我可以做 if (whatever) { $a >> $b} else{ gmp_shiftr($a, $b) }?
      • 尝试添加$bignum &lt;&lt; $b,然后执行&gt;&gt; $b,然后减去$bignum。 bignum 是一个足够大的常数,因此第一个结果总是 >=0;它会做你想做的事(并且不会影响 >= 0 个结果)。
      猜你喜欢
      • 2011-10-12
      • 1970-01-01
      • 2019-10-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-08-30
      • 2022-06-10
      • 1970-01-01
      相关资源
      最近更新 更多