计算绝对值,可以不需要if、else?

最近头脑发热,想实现一下不需要if、else语句就能计算出一个数绝对值的算法:
位运算的基本辅助算法:


	public static final long 	MAX_64 = 0xFFFFFFFFFFFFFFFFL;
	public static final int 	MAX_32 = 0xFFFFFFFF;
	public static final long	FULL_0 = MAX_64 - 1;
	
	public static void main(String args[])
	{
		System.out.println(abs(354359));
		printBin(3, 16);
	}
	
	/**设置数字上某一位的数值为0*/
	public static long setBin_0(long data,int index)
	{
		return ~(1 << index) & data;
	}
	
	/**设置数字上某一位的数值为1*/
	public static long setBin_1(long data,int index)
	{
		return 1 << index | data;
	}
	
	/**获取数字上某一位的数值*/
	public static long getBin(long data,int index)
	{
		return data >> index & 1;
	}
	
	/**以二进制方式打印数字*/
	public static String printBin(long num,int count)
	{
		String str = "";
		for (int i = count-1; i >= 0; i--) 
		{
			str += getBin(num,i);
			if(i % 8==0 && i != 0)
			{
				str += ",";
			}
			else if(i % 4==0)
			{
				str += " ";
			}
		}
		System.out.println(str);
		return str;
	}


设计思路:

首先明白,数字在计算机上是以二进制存储的,正数(无符号数)、负数(有符号数)的区别在于最高位上是否为1,而且正数储存方式为原码、负数是以补码的方式储存的。最后就是通过符号位,对数字进行筛选。

int num = 5443; 

正数的二进制原码表示 0000 0000,0000 0000,0001 0101,0100 0011 


int num = -5443; 

负数的二进制原码表示 1000 0000,0000 0000,0001 0101,0100 0011 

负数的二进制反码表示 1111 1111,1111 1111,1110 1010,1011 1100

负数的二进制补码表示 1111 1111,1111 1111,1110 1010,1011 1101 (在反码的基础上+1)


1、可以看到一个数的负数形式,是通过这个数的正数,经过符号位变成1,然后'原码'>‘反码’>‘补码’的过程转换的。那么将一个负数装成正数就是这个过程的逆过程。

2、要注意的是,我们不能使用if、else来判断(这样的? :三元运算符也不行),那么我们的算法就要求能够适应正数、负数的“一波流”了!


不是我耍赖,我们先用if、else的写法来演示一下,这样更加清晰:

	public static long absIf_else(long num)
	{
		byte signBit = (byte)getBin(num,63);//获取符号位
		if(signBit == 1)//负数
		{
			num -= 1;
			num ^= MAX_64;//取反
		}
		else//否则不做任何事
		{
			
		}
		return num;
	}

测试通过!

		System.out.println(absIf_else(-354359));//354359
		System.out.println(absIf_else(354359));//354359

然后再把算法变成一波流!

看代码:

if(signBit == 1)//负数
{
num -= 1;
num ^= MAX_64;//取反
}

1、num -= 1;我们可以用num -= signBit代替,因为如果是正数signBit=0,减去0当然是保持不变的。

2、num ^= MAX_64;可以把MAX_64*signBit,因为如果是正数signBit=0,相乘等于0,原数与0异或运算保持不变。


所以一波流的算法如下:

byte signBit = (byte)getBin(num,63);//符号位
num -= signBit;//补码转反码
num ^= (MAX_64 * signBit);//通过异或运算、反码转原码


实现的函数:

	public static long abs(long num)
	{
		byte signBit = (byte)getBin(num,63);//符号位
		num -= signBit;//补码转反码
		num ^= (MAX_64 * signBit);//通过异或运算、反码转原码
		return num;
	}


	public static double abs(double floatNum)
	{
		long num = Double.doubleToLongBits(floatNum);
		return Double.longBitsToDouble(setBin_0(num, 63));
	}

完毕

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值