似乎存在某种误解,认为这是一场竞赛。 我正在努力完成任务,现在我已经坚持了一个小时。
/*
* 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
。因此,否定我可以得到相反的效果。
同样,我知道!(x^y)
相当于x==y
。
然而,
做!(greater)|(!(x^y))
并没有返回正确的值。
我搞砸了哪里?我觉得我缺少一点点逻辑。
答案 0 :(得分:4)
由于溢出,这些功能无法完全发挥作用,因此我就是如何解决问题的。诶...
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;
}
答案 1 :(得分:2)
如果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);
}
说明:总体策略是将输入的符号位视为逻辑上与其余位,&#34;值位,&#34;并且仅在值位上执行前一示例中的减法。在这种情况下,我们只需要执行减法,其中两个输入既是负的也是非负的。这避免了算术溢出条件。
由于严格来说int
的大小在运行时是未知的,我们使用std::numeric_limits<int>::max()
作为值位的方便掩码。符号位的掩码只是值位的逐位否定。
转到<=
的实际表达式,我们将每个子表达式中符号位的逐位掩码sm
分解出来,并将操作推送到表达式的外部。当x & ~y
为负数且x
为非负数时,逻辑表达式y
的第一项为真。当两者都是负数或两者都是非负数时,下一个术语~(x ^ Y)
的第一个因子是正确的。当~((y & vm) + ~(x & vm) + 1))
为非负数时,第二个因子y - x
为真,换句话说x <= y
,忽略符号位。这两个术语是或者是,所以使用c ++逻辑表达式语法我们有:
x < 0 && y >= 0 || (x < 0 && y < 0 || x >= 0 && y >= 0) && y - x >= 0
!!
最外层运算符将凸起符号位转换为1
。最后,这是Modern 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);
}
答案 2 :(得分:2)
真的很喜欢Yanagar1的回答,这很容易理解。
实际上,我们可以删除这些移位运算符,并使用De Morgan的定律,这会将运算符的数量从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 :(得分:0)
这是我的实现方式(花了大约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
?因为可能会发生溢出。因此,我必须尽早返回以避免溢出。
答案 4 :(得分:0)
受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 - x
,然后逻辑取反结果的符号位,当{{1}时,我们可以得到0
},以及y < x
时的1
。但是存在潜在的溢出情况(当y >= x
和y
具有相反的符号,即-x
和y
具有相同的符号时,不会发生溢出):
x
所以当符号不同时,我们需要小心。