在不使用abs函数或if语句的情况下获取绝对值

问题描述 投票:50回答:18

我在考虑如何在不使用if语句和abs()的情况下获得整数的绝对值。起初我使用左移位(<<),试图将负号移出范围,然后将位移回原位,但不幸的是它对我不起作用。请让我知道它为什么不起作用以及其他替代方法。

c bit-manipulation
18个回答
1
投票

如果你的语言允许bool为int cast(C / C ++之类):

y = condition ? value_if_true : value_if_false;

0
投票

使用三元运算符:

value = value > 0 ? value: ~value + 1

0
投票

那个怎么样:

 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

我知道这有点晚了但是我遇到了同样的问题并且降落在这里,希望这会有所帮助。


0
投票

将符号位移出并向右移位(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);
}

0
投票

没有分支或乘法:

#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.
}

0
投票

这个如何:

-1 * n

-2
投票

你必须按位而不是加法组合。


-3
投票

有什么问题:

f(x) = (x*x)/x

使用负减等于加原理


-3
投票

如果你想要一种不太昂贵的纯数学方法,试试吧

function abs(auto x) {return ((x*x)/x);}

或者在C ++中

qazxswpoi

2
投票

请尝试以下方法:

abs()

2
投票

这是另一种没有(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

2
投票

没有看到这一个。对于二进制补码表示和32位整数

float absB(float n) {
    return n - n * 2.0f * ( n < 0.0f );
}
© www.soinside.com 2019 - 2024. All rights reserved.