获取绝对值,而不使用 ABS 函数或 if 语句
get absolute value without using abs function nor if statement
我在想如何在不使用语句或abs()
的情况下获取整数if
绝对值。起初我使用左移位(<<
(,试图将负号移出范围,然后将位移回原位,但不幸的是它对我不起作用。请让我知道为什么它不起作用以及其他替代方法。
来自 bit twiddling hacks:
int v; // we want to find the absolute value of v
unsigned int r; // the result goes here
int const mask = v >> sizeof(int) * CHAR_BIT - 1;
r = (v + mask) ^ mask;
int abs(int v)
{
return v * ((v>0) - (v<0));
}
此代码将 v
的值乘以 -1
或 1
得到 abs(v(。因此,括号内将是 -1
或 1
.
如果v
为正,则表达式 (v>0)
为真,并且值1
,而(v<0)
为假(值 0 表示假(。因此,当v
为正时((v>0) - (v<0)) = (1-0) = 1
.整个表达是:v * (1) == v
.
如果v
为负数,则表达式 (v>0)
为假,值将0
,而(v<0)
为真(值 1(。因此,对于负v
,((v>0) - (v<0)) = (0-1) = -1
。整个表达方式是:v * (-1) == -v
.
当v == 0
时,(v<0)
和 (v>0)
的计算结果都将为 0,留下:v * 0 == 0
。
Branchless:
int abs (int n) {
const int ret[2] = { n, -n };
return ret [n<0];
}
注4.7 积分换算/4:[...] If the source type is bool, the value false is converted to zero and the value true is converted to one.
我在 C 中尝试了这段代码,它可以工作。
int abs(int n){
return n*((2*n+1)%2);
}
希望这个答案会有所帮助。
32 位有符号整数 (Java(,你可以这样写:
public static int abs(int x)
{
return (x + (x >> 31)) ^ (x >> 31);
}
没有乘法,没有分支。
顺便说一句,return (x ^ (x >> 31)) - (x >> 31);
也可以工作,但它已获得专利。是的!
注意:此代码可能需要比条件语句(8 位版本(长 10 倍以上的时间。这对于硬件编程系统C等可能很有用
尝试以下操作:
int abs(int n)
{
return sqrt(n*n);
}
没看到这个。对于 2 的补码表示和 32 位 int
( n >> 31 | 1 ) * n
没有分支或乘法:
int abs(int n) {
int mask = n >> 31;
return (mask & -n) | (~mask & n);
}
这是另一种没有abs()
的方法,如果或任何逻辑/条件表达式:假设 int 在这里是 32 位整数。这个想法很简单:(1 - 2 * sign_bit)
将转换sign_bit = 1 / 0 to -1 / 1
.
unsigned int abs_by_pure_math( int a ) {
return (1 - (((a >> 31) & 0x1) << 1)) * a;
}
如果你的语言允许 bool 到 int cast(C/C++ like(:
float absB(float n) {
return n - n * 2.0f * ( n < 0.0f );
}
以您认为的方式将有符号整数移位是未定义的行为,因此不是一种选择。相反,您可以这样做:
int abs(int n) { return n > 0 ? n : -n; }
没有if
语句,只是一个条件表达式。
有多种原因导致左移标志位和右移回原位(v << 1 >> 1
(:
- 左移 具有负值的有符号类型具有未定义的行为,因此根本不应使用它。
- 将值转换为
unsigned
将具有预期的效果:如果没有填充位,(unsigned)v << 1 >> 1
确实会删除符号位,但结果值是仅在具有符号+幅度表示的系统上v
的绝对值,这在当今已经非常罕见。 在无处不在 2 的补码架构上,负v
的结果值为INT_MAX+1-v
不幸的是,Hasturkun的解决方案具有实现定义的行为。
以下是为有符号值具有 2 补码表示的系统完全定义的变体:
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;
这个呢:
#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.
}
位移(原则上(是实现定义的,但转换为更广泛的有符号整数类型将扩展符号位。如果您将 hi-bit 解释为整数,它们将是 0 或 -1,这将允许您反转 2 的补码:
int32_t abs(int32_t in)
{
int64_t in64 = (int64_t)in;
int32_t* ptr = (int32_t*)&in64;
int32_t hi = *(++ptr); // assumes little-endian
int32_t out = (in ^ hi) - hi;
return out;
}
上述机制是在启用优化的情况下编译朴素实现的结果:
mov eax,ecx
cdq
xor eax,edx
sub eax,edx
一个避免位移的简单方法:
value -= (value < 0) * value * 2;
- 如果
value
为正数,则value < 0
的计算结果为0
,因此乘法结果为0
。没有什么是从value
中减去的. - 如果
value
0
,乘法结果也是0
。 - 如果
value
为负数,则value < 0
为true
,其计算结果为1
,然后乘以value * 2
。从本质上讲,你正在从价值中减去价值的两倍,从而获得相应的正值。
:
value = value > 0 ? value: ~value + 1
它基于负数存储为 2 的补码到那里的正等价数的事实,并且可以通过首先构建 1 的补码并添加 1 来构建 2 的补码,因此
5 -> 0000 0101b
-5 -> (1111 1010b) + 1 -> 1111 1011b
我所做的基本上就是为了扭转这种情况,所以
-5 -> 1111 1011b
5 -> (0000 0100b) + 1 -> 0000 0101b
我知道有点晚了,但只是遇到了同样的问题并降落在这里,希望这有帮助。
使用除法(和更广泛的数学(来形成一个"if"。 也许效率不高,但无分支。
int abs_via_division(int v) {
// is_neg:0 when v >= 0
// 1 when v < 0
int is_neg = (int) ((4LL * v) / (4LL * v + 1));
return v * (1 - is_neg*2);
}
适用于long long
比int
宽时的所有int
,除了通常的|INT_MIN|
麻烦。
使用三元运算符:
y = condition ? value_if_true : value_if_false;
- "error: no matching function for call to"构造函数错误
- 什么时候调用组成单元对象的析构函数
- 继承函数的重载解析
- 为什么随机数生成器不在void函数中随机化数字,而在main函数中随机化
- C++模板来检查友元函数的存在
- 递归函数计算序列中的平方和(并输出过程)
- 对RValue对象调用的LValue ref限定成员函数
- C++17复制构造函数,在std::unordereded_map上进行深度复制
- 将数组作为参数传递给函数安全吗?作为第三方职能部门,可以探索他们想要的之外的其他元素
- 在C++STL中是否有Polyval(Matlab函数)等价物?
- 为什么使用 "this" 指针调用派生成员函数?
- 将对象数组的引用传递给函数
- cpp 使用 abs() 函数和 size_t
- 如何减少 abs 函数的数量
- 无法在 abs 函数 c++ 中使用字符串长度函数
- 标准库函数 abs() 在不同C++编译器上的异常行为
- ABS 函数在 C++ 中没有给出正确的答案
- 在 std::abs 函数上
- 获取绝对值,而不使用 ABS 函数或 if 语句
- iostream为什么定义abs函数,以及如何停止它