如何在不使用if
条件语句的情况下计算整数的绝对值?我猜我们需要使用一些位运算。有人可以帮忙吗?
如何在不使用if
条件语句的情况下计算整数的绝对值?我猜我们需要使用一些位运算。有人可以帮忙吗?
1
位都向左移动,而对于正数则将所有0
位向左移动(但请注意,在C或C++中实际的>>
运算符的行为对于负数是有实现定义的,但通常也会执行算术移位,但让我们假设伪代码或实际的硬件指令,因为它听起来像是作业):mask = x >> 31;
因此,对于负数,我们得到的是111...111
(-1),对于正数,我们得到的是000...000
(0)。
现在,我们将其与x
进行异或运算,对于mask=111...111
(负数),得到NOT的行为,对于mask=000...000
(正数),得到no-op(无操作)。
x = x XOR mask;
最后,我们要对掩码进行减法运算,对于负数结果为+1,对于正数结果为+0或无操作:
x = x - mask;
那么对于正数,我们执行0的异或操作和0的减法,从而得到相同的数字。而对于负数,我们有(NOT x) + 1
,在使用二进制补码表示时,这恰好是-x
。
if
值是否小于0并执行i = i + (i * -2)
来实现i
的绝对值。 - sixty4bit将掩码设置为整数右移31位(假设整数存储为二进制补码32位值,并且右移运算符会进行符号扩展)。
mask = n>>31
将掩码与数字进行异或运算
mask ^ n
从步骤2的结果中减去掩码并返回结果。(mask^n) - mask
abs(〜int)- abs(int)
的结果为0
,而您的解决方案要求:abs(abs(〜int)- abs(int))
为1。 - dheinint
为32位。int my_abs(int x)
{
int y = (x >> 31);
return (x ^ y) - y;
}
我们也可以这样执行上述操作:
return n*(((n>0)<<1)-1);
其中n
是需要计算绝对值的数字。
/**
* Calculates the absolute value of a double.
* @param x An 8-byte floating-point double
* @return A positive double
* @note Uses bit manipulation and does not care about NaNs
*/
double abs(double x)
{
union{
uint64_t bits;
double dub;
} b;
b.dub = x;
//Sets the sign bit to 0
b.bits &= 0x7FFFFFFFFFFFFFFF;
return b.dub;
}
在发现这个问题之前,我自己写了一个。
我的答案可能较慢,但仍然有效:
int abs_of_x = ((x*(x >> 31)) | ((~x + 1) * ((~x + 1) >> 31)));
int absVal(int x) {
return ((x >> 31) + x) ^ (x >> 31);
}
pxor mm1, mm1 ; set mm1 to all zeros
psubw mm1, mm0 ; make each mm1 word contain the negative of each mm0 word
pmaxswmm1, mm0 ; mm1 will contain only the positive (larger) values - the absolute value
pabsw
。 - haroldpublic static long abs(long d) => (d + (d >>= 63)) ^ d;
public static int abs(int d) => (d + (d >>= 31)) ^ d;
上面展示的代码取决于在计算左侧期间更新的注意:
0x80000000(int.MinValue)
和0x8000000000000000(long.MinValue)
:与本页上显示的所有其他按位/非分支方法一样,这会给出单个非数学结果
abs(int.MinValue) == int.MinValue
(对于long.MinValue
也是如此)。这些表示结果值为负的唯一情况,即MSB的two's-complement结果为1
- 也是输入值未更改返回的唯一情况。我认为这个重要点在本页其他地方没有提到。
d
值用于右侧的xor的值。对于C#程序员来说,这似乎是显而易见的。他们习惯于看到像这样的代码,因为.NET正式包含了一个强大的内存模型,严格保证了正确的获取顺序。我提到这一点的原因是因为在C
或C++
中,人们可能需要更加谨慎。后者的内存模型相对宽松,这可能允许某些编译器优化发出无序获取。显然,在这种情况下,获取顺序的敏感性将代表一种正确性危险。如果您不想依赖于符号扩展的实现来进行右位移,您可以修改计算掩码
的方式:
mask = ~((n >> 31) & 1) + 1
然后按照之前的答案所演示的步骤继续进行:
(n ^ mask) - mask