Sid*_*Sid 1 java bit-manipulation absolute-value
我想实现一个函数来获取java中数字的绝对值:如果是正数则不执行任何操作,如果是负数则转换为正数.
我想这只是使用位操作而不是数字比较器.
请帮忙
否定:
-n
Run Code Online (Sandbox Code Playgroud)
与两个补码相同:
~n + 1
Run Code Online (Sandbox Code Playgroud)
问题在于你只想在值<0时否定.你可以通过使用逻辑移位来查看是否设置了MSB:
n >>> 31
Run Code Online (Sandbox Code Playgroud)
补码与具有全1的XOR相同,类似于(对于4位整数):
~1010 == 1010 ^ 1111
Run Code Online (Sandbox Code Playgroud)
我们可以通过算术右移获得一个掩码:
n >> 31
Run Code Online (Sandbox Code Playgroud)
绝对值说:
所以把它放在一起我们可以做到以下几点:
static int abs(int n) {
return (n ^ (n >> 31)) + (n >>> 31);
}
Run Code Online (Sandbox Code Playgroud)
其中计算:
我不确定没有添加就可以轻松实现.增加涉及任意数量的携带,即使是简单的增量.
例如2 + 1没有携带:
10 + 1 == 11
Run Code Online (Sandbox Code Playgroud)
但47 + 1有4个进位:
101111 + 1 == 110000
Run Code Online (Sandbox Code Playgroud)
使用按位/位移进行添加和进位基本上只是循环展开并且没有意义.
(编辑!)
只是愚蠢,这是一个增量和携带:
static int abs(int n) {
int s = n >>> 31;
n ^= n >> 31;
int c;
do {
c = (n & s) << 1;
n ^= s;
} while((s = c) != 0);
return n;
}
Run Code Online (Sandbox Code Playgroud)
它的工作方式是翻转第一位,然后一直翻转直到找到0.所以那时工作只是展开循环.环体可以用有点荒谬的复合单线表示.
static int abs(int n) {
int s = n >>> 31;
n ^= n >> 31;
int c = (n & s) << 1;
c = ((n ^= s) & (s = c)) << 1; // repeat this line 30 more times
n ^= s;
return n;
}
Run Code Online (Sandbox Code Playgroud)
所以有一个abs只使用按位和位移.
这些并不比Math.abs快.Math.abs只是返回n < 0 ? -n : n
,这是微不足道的.实际上,循环展开相比之下完全糟糕.我猜是好奇心.这是我的基准:
Math.abs: 4.627323150634766ns shift/xor/add abs: 6.729459762573242ns loop abs: 12.028789520263672ns unrolled abs: 32.47122764587402ns bit hacks abs: 6.380939483642578ns
(这里显示的是非专利的,这是一个非专利的,与我的基本相同的想法,除了有点难以理解.)
归档时间: |
|
查看次数: |
3093 次 |
最近记录: |