我在考虑如何在不使用if
语句和abs()
的情况下获得整数的绝对值。起初我使用左移位(<<
),试图将负号移出范围,然后将位移回原位,但不幸的是它对我不起作用。请让我知道它为什么不起作用以及其他替代方法。
如果你的语言允许bool为int cast(C / C ++之类):
y = condition ? value_if_true : value_if_false;
使用三元运算符:
value = value > 0 ? value: ~value + 1
那个怎么样:
5 -> 0000 0101b
-5 -> (1111 1010b) + 1 -> 1111 1011b
它基于这样一个事实,即负数存储为正数等价的2的补码,并且可以通过首先构建1的补码并加1来构建2的补码,所以
-5 -> 1111 1011b
5 -> (0000 0100b) + 1 -> 0000 0101b
我所做的基本上是为了扭转这一局面,所以
v << 1 >> 1
我知道这有点晚了但是我遇到了同样的问题并且降落在这里,希望这会有所帮助。
将符号位移出并向右移位(unsigned
)有多种原因:
(unsigned)v << 1 >> 1
将产生预期的效果:v
确实摆脱了符号位,如果没有填充位,但结果值是v
的绝对值仅在具有符号+幅度表示的系统上,这是非常罕见的如今。在无处不在的2的补码结构中,负INT_MAX+1-v
的结果值是int v; // we want to find the absolute value of v
unsigned int r; // the result goes here
unsigned int mask = -((unsigned int)v >> (sizeof(unsigned int) * CHAR_BIT - 1));
r = ((unsigned int)v + mask) ^ mask;
不幸的是,Hasturkun的解决方案具有实现定义的行为。
以下是为具有带符号值的2的补码表示的系统完全定义的变体:
int abs(int n) {
int mask = n >> 31;
return (mask & -n) | (~mask & n);
}
没有分支或乘法:
#include <climits>
long abs (int n) { // we use long to avoid issues with INT MIN value as there is no positive equivalents.
const long ret[2] = {n, -n};
return ret[n >> (sizeof(int) * CHAR_BIT - 1)]; // we use the most significant bit to get the right index.
}
这个如何:
-1 * n
你必须按位而不是加法组合。
有什么问题:
f(x) = (x*x)/x
使用负减等于加原理
如果你想要一种不太昂贵的纯数学方法,试试吧
function abs(auto x) {return ((x*x)/x);}
或者在C ++中
qazxswpoi
请尝试以下方法:
abs()
这是另一种没有(1 - 2 * sign_bit)
的方法,如果也没有任何逻辑/条件表达式:假设int在这里是32位整数。这个想法很简单:sign_bit = 1 / 0 to -1 / 1
将转换unsigned int abs_by_pure_math( int a ) {
return (1 - (((a >> 31) & 0x1) << 1)) * a;
}
。
( n >> 31 | 1 ) * n
没有看到这一个。对于二进制补码表示和32位整数
float absB(float n) {
return n - n * 2.0f * ( n < 0.0f );
}