繁体   English   中英

按位小于或等于

[英]Bitwise Less than or Equal to

似乎有人误以为这是一场比赛。 我正在尝试完成一项作业,现在我已经坚持了一个小时。

 /*
     * isLessOrEqual - if x <= y  then return 1, else return 0 
     *   Example: isLessOrEqual(4,5) = 1.
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 24
     *   Rating: 3
     */
    int isLessOrEqual(int x, int y)
    {
        int greater = (x + (~y + 1))>>31 & 1;
        return !(greater)|(!(x^y));

    }

我只能按照评论中的说明使用按位运算符。 我不知道如何解决x <= y

我的思考过程是我可以将 x 设置为它的二进制补码 ( ~x +1 ) 并将其与Y相加。 如果为负,则X大于Y 因此,通过否定 I 可以获得相反的效果。

同样,我知道!(x^y)等同于x==y 但是,执行!(greater)|(!(x^y))不会返回正确的值。

我哪里搞砸了? 我觉得我缺少一点逻辑。

由于溢出,这些功能不能完全工作,所以我就是这样解决问题的。 呃...

int isLessOrEqual(int x, int y) {
int diff_sgn = !(x>>31)^!(y>>31);      //is 1 when signs are different
int a = diff_sgn & (x>>31);            //diff signs and x is neg, gives 1
int b = !diff_sgn & !((y+(~x+1))>>31); //same signs and difference is pos or = 0, gives 1
int f = a | b;
return f;
}

如果x > y ,则y - x(y + (~x + 1))将为负,因此高位将为 1,否则为 0。但我们希望x <= y ,这是否定这个的。

    /*
     * isLessOrEqual - if x <= y  then return 1, else return 0 
     *   Example: isLessOrEqual(4,5) = 1.
     *   Legal ops: ! ~ & ^ | + << >>
     *   Max ops: 24
     *   Rating: 3
     */
    int isLessOrEqual(int x, int y)
    {
        return !(((y + (~x + 1)) >> 31) & 1);
    }

更好的是,删除移位运算符并在高位上使用位掩码:

    int isLessOrEqual(int x, int y)
    {
        return !((y + (~x + 1)) & 0x80000000);
    }

编辑:

作为评论者指出,上述版本容易出现算术溢出错误。 这是涵盖边缘情况的另一个版本。

#include <limits>
int isLessOrEqual(int x, int y)
{
    static int const vm = std::numeric_limits<int>::max();
    static int const sm = ~vm;

    return  !! ((x & ~y | ~(x ^ y) & ~((y & vm) + ~(x & vm) + 1)) & sm);
}

解释:总体策略是将输入的符号位视为与其余位(“值位”)在逻辑上不同,并像前面的示例一样仅对值位执行减法运算。 在这种情况下,我们只需要在两个输入均为负或均为非负的情况下执行减法。 这避免了算术溢出情况。

由于严格来说int的大小在运行时是未知的,我们使用std::numeric_limits<int>::max()作为值位的方便掩码。 符号位的掩码只是值位的逐位否定。

转向<=的实际表达式,我们分解出每个子表达式中符号位的位掩码sm并将操作推到表达式的外部。 x为负且y为非负时,逻辑表达式x & ~y的第一项为真。 下一项的第一个因素~(x ^ Y)当两者都为负或都为非负时为真。 y - x为非负时,第二个因素~((y & vm) + ~(x & vm) + 1))为真,换句话说, x <= y忽略符号位 这两个术语是 or'd,所以使用 c++ 逻辑表达式语法我们有:

x < 0 && y >= 0 || (x < 0 && y < 0 || x >= 0 && y >= 0) && y - x >= 0

!! 最外层运算符将升高的符号位转换为1 最后,这是现代 C++ 模板化的constexpr版本:

template<typename T>
constexpr T isLessOrEqual(T x, T y)
{
    using namespace std;
    // compile time check that type T makes sense for this function
    static_assert(is_integral<T>::value && is_signed<T>::value, "isLessOrEqual requires signed integral params");

    T vm = numeric_limits<T>::max();
    T sm = ~vm;

    return  !! ((x & ~y | ~(x ^ y) & ~((y & vm) + ~(x & vm) + 1)) & sm);
}

真的很喜欢Yanagar1的回答,很容易理解。

实际上,我们可以去除那些移位运算符并使用德摩根定律,将运算符的数量从 15 减少到 11。

long isLessOrEqual(long x, long y) {
  long sign = (x ^ y);               // highest bit will be 1 if different sign
  long diff = sign & x;              // highest bit will be 1 if diff sign and neg x
  long same = sign | (y + (~x + 1)); // De Morgan's Law with the following ~same
                                     // highest bit will be 0 if same sign and y >= x
  long result = !!((diff | ~same) & 0x8000000000000000L); // take highest bit(sign) here
  return result;
}

这是我的实现(花费大约 3 个小时...)

int
isLessOrEqual(int x, int y)
{
    int a = y + ~x + 1;
    int b = a & 1 << 31 & a; // !b => y >= x, but maybe overflow
    int c = !!(x & (1 << 31)) & !(y & (1 << 31)); // y > 0, x < 0
    int d = !(x & (1 << 31)) & !!(y & (1 << 31)); // x > 0, y < 0

    int mask1 = !c + ~0;

    // if y > 0 && x < 0, return 1. else return !b
    int ans = ~mask1 & !b | mask1 & 1;

    int mask2 = !d + ~0;

  // if y < 0 && x > 0, return 0, else return ans
    return ~mask2 & ans | mask2 & 0;
}
  • y - x == y + ~x + 1

  • a & 1 << 31 & a是从!(!(a & (1 << 31)) | !a)

逻辑是:

if `y > 0 && x < 0`
    return true  
if `x > 0 && y < 0`
    return false

return y >= x

为什么不直接y >= x 因为可能会发生溢出。 所以我必须早点返回以避免溢出。

受到Yanagar1's answer 的启发,这是我的实现:

int isLessOrEqual(int x, int y) {

    int indicator = !((y + (~x + 1)) >> 31); // negation of the result of y - x, 0 when y < x, -1 when y >= x
    int xsign = x >> 31; // -1 when x < 0, 0 when x >= 0
    int ysign = y >> 31; // -1 when y < 0, 0 when y >= 0
    int xbool = !xsign; // 0 when x < 0, 1 when x >= 0
    int ybool = !ysign; // 0 when y < 0, 1 when y >= 0
    int result = (!(xbool ^ ybool)) & indicator;
    return result | (ybool & !xbool);
}

解释:将 x (~x + 1) 2 的补码求反加到 y 本质上是在计算y - x ,然后对结果的符号位进行逻辑取反,当y < x时我们可以有0 ,当y >= x时我们可以有1 但也有潜在的溢出情况(当y-x符号相反,即yx符号相同时,不会发生溢出):

|-----------|------------------------|------------------------|
|           |         y > 0          |         y < 0          |
|-----------|------------------------|------------------------|
|   x > 0   |           ok           | overflow when y = TMin |
|-----------|------------------------|------------------------|
|   x < 0   | overflow when x = TMin |           ok           |
|-----------|------------------------|------------------------|

所以当标志不同时我们需要小心。

可能我的解决方案很愚蠢。

int isLessOrEqual(int x, int y) {
  /*
   * A: sign bit of x   B: sign bit of y    C:A == B  Result          Rearrange the result(Expeced)
   * 0                  0                   1         y - x >= 0      (y + (~x+1) >= 0) & 1 | 0 => (y + (~x+1) >= 0) & C | !(B | C)
   * 0                  1                   0         0               (y + (~x+1) >= 0) & 0 | 0 => (y + (~x+1) >= 0) & C | !(B | C)
   * 1                  0                   0         1               (y + (~x+1) >= 0) & 0 | 1 => (y + (~x+1) >= 0) & C | !(B | C)
   * 1                  1                   1         y - x >= 0      (y + (~x+1) >= 0) & 1 | 0 => (y + (~x+1) >= 0) & C | !(B | C)
   * But, minus operator is illegal. So (y - x) placed by (y + (-x)).
   * You know -x == (~x + 1).
   * If we know *x* and *y* have different sign bits, the answer is determinated and the (y-x >= 0) was useless.
   * finally, the work like designing digital circuit. produce a final expression.
   */
  int A = (x >> 31) & 1;
  int B = (y >> 31) & 1;
  int C = !(A ^ B);
  int greatOrEqual0 = (!(((y + (~x + 1)) >> 31) ^ 0));
  return (greatOrEqual0 & C) | !(B | C);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM