如何在java中使用位操作获得数字的绝对值

如何在java中使用位操作获得数字的绝对值,java,bit-manipulation,absolute-value,Java,Bit Manipulation,Absolute Value,我想在java中实现一个函数来获取一个数字的绝对值:如果它是正的,什么也不做,如果它是负的,转换成正的 我只想使用位操作,不使用数字比较器 请帮助这取决于您使用的号码类型。对于int,使用 int sign = i >> 31; 这将获取符号位,正数为0,负数为1。对于其他基元类型,将31替换为基元使用的位数减去1 然后可以在if语句中使用该符号 if (sign == 1) i = ~i + 1; 你可以通过取一个2的赞美数字的逻辑否定来将它变成正数或负数 i = ~i

我想在java中实现一个函数来获取一个数字的绝对值:如果它是正的,什么也不做,如果它是负的,转换成正的

我只想使用位操作,不使用数字比较器


请帮助

这取决于您使用的号码类型。对于int,使用

int sign = i >> 31;
这将获取符号位,正数为0,负数为1。对于其他基元类型,将31替换为基元使用的位数减去1

然后可以在if语句中使用该符号

if (sign == 1)
    i = ~i + 1;

你可以通过取一个2的赞美数字的逻辑否定来将它变成正数或负数

i = ~i; // i equals not i
您可以使用
Math.max()
函数始终获得正值

public static int abs(int i) {
    return Math.max(i,~i);
}
那么一个否定:

-n
与两者的补语相同:

~n + 1
问题是,只有当值小于0时,才需要求反。通过使用逻辑移位来查看是否设置了MSB,您可以发现:

n >>> 31
补码与所有1的XOR相同,类似于(对于4位整数):

我们可以用算术右移得到一个掩模:

n >> 31
绝对值表示:

  • 如果n<0,则取反(取补码并加1)
  • 否则,什么也不要做
因此,把它放在一起,我们可以做到以下几点:

static int abs(int n) {
    return (n ^ (n >> 31)) + (n >>> 31);
}
其中计算:

  • 如果n小于0,则将其与所有1进行异或运算,并向其中添加1
  • 否则,将其与所有0进行异或运算,并向其中添加0
我不确定有没有一个简单的方法来做它没有额外的。加法涉及任何进位数,即使是简单的增量

例如,2+1没有进位:

10 + 1 == 11
但47+1有4个进位:

101111 + 1 == 110000
按位/位移位进行加法和进位运算基本上只是一个循环展开,毫无意义

(编辑!)

愚蠢的是,这里有一个增量和进位:

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;
}
static int abs(int n){
int s=n>>>31;
n^=n>>31;
INTC;
做{
c=(n&s)>>31;
n^=n>>31;

int c=(n&s)我想你会发现这首小曲正是你想要的:

int abs(int v) {
    int mask = v >> Integer.SIZE - 1;

    return v + mask ^ mask;
}
它基于绝对值方程,不使用比较运算。如果不允许使用加法,则
(v^mask)-mask
是一种替代方法。此函数的值相当值得怀疑;因为它几乎与Math.abs的实现一样清晰,而且只稍微快一点(至少在i7上):

  • v+mask^mask
    :2.0844380704220384 abs/ns
  • (v^mask)-mask
    :2.0819764093030244 abs/ns
  • Math.abs
    :2.2636355843860656 abs/ns
  • 下面是一个测试,它证明它可以在整个整数范围内工作(测试在Java 7 update 51下的i7处理器上运行不到2分钟):

    封装测试;
    导入org.hamcrest.core.Is;
    导入org.junit.Assert;
    导入org.junit.Test;
    公开课{
    @试验
    公开无效测试(){
    长处理计数=0L;
    长numberOfIntegers=1L>Integer.SIZE-1;
    返回v+掩码^mask;
    }
    }
    
    此问题可分为两个简单步骤: 1. 如果>=0,则只返回数字

    2. 如果小于0(即负),则翻转指示数字为负的第一位。这可以通过使用-1和数字的异或运算轻松完成;然后简单地添加+1以处理偏移量(有符号整数从-1开始,而不是从0开始)


    我想第一部分,我只是想知道
    I=-I
    的按位替代方案,其实没有。你可以做I=~I+1,但这仍然不是完全按位的。很好的解决方案。我的解决方案仍然需要一个比较。谢谢。我想没有maskforgiggles是没有办法的,我添加了一个没有添加的版本。请注意将
    Math.abs(Integer.MIN\u VALUE)
    生成
    -2147483648
    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;
    }
    
    Math.abs: 4.627323150634766ns shift/xor/add abs: 6.729459762573242ns loop abs: 12.028789520263672ns unrolled abs: 32.47122764587402ns bit hacks abs: 6.380939483642578ns
    int abs(int v) {
        int mask = v >> Integer.SIZE - 1;
    
        return v + mask ^ mask;
    }
    
    package test;
    
    import org.hamcrest.core.Is;
    import org.junit.Assert;
    import org.junit.Test;
    
    public class AbsTest {
    
        @Test
        public void test() {
            long processedCount = 0L;
            long numberOfIntegers = 1L << Integer.SIZE; //4294967296L
            int value;
    
            for (value = Integer.MIN_VALUE; processedCount < numberOfIntegers; value++) {
                Assert.assertEquals((long) abs(value), (long) StrictMath.abs(value));
                if (processedCount % 1_000_000L == 0L) {
                    System.out.print(".");
                }
                processedCount++;
            }
            System.out.println();
            Assert.assertThat(processedCount, Is.is(numberOfIntegers));
            Assert.assertThat(value - 1, Is.is(Integer.MAX_VALUE));
        }
    
        private static int abs(int v) {
            int mask = v >> Integer.SIZE - 1;
    
            return v + mask ^ mask;
        }
    
    }
    
    public static int absolute(int a) {
        if (a >= 0) {
            return a;
        } else  {
            return (a ^ -1) + 1;
        }
    }