scala及java中的无符号右移运算需要注意的坑

在一个数据处理逻辑中追踪一个bug,最后定位在一行右移运算上,结果不是预期值

var oldbyte:Byte = 0  //原字节数值

var bitcount = 1          //右移位数,下面都是用1测试

var newbyte:Byte = (oldbyte >> bitcount).toByte  //新字节数值

在oldbyte>=0时一切正常

当oldbyte<0(也就oldbyte作为无符号数值>127)结果得到了非预期值

 

如:oldbyte = 0xfb  //二进制 1111 1011,因为byte类型为有符号数,所以看到的是-5

            预期右移一位后得到 0111 1101 ,即 125,结果 newbyte = -3

       0xfb 二进制 1111 1011,最高位1表符号,后面是111 1011是5(_000 0101)的补码

结果-3 ,二进制 1111 1101,即最高位不是补0,而是补1

这也就是右移操作符>>,所谓的符号位扩展,高位补1

 

那该怎么得到预期值呢,复习了语法基础,发现另外还有一个无符号右移运算符>>>

即将原数视为无符号数,高位右移后补0,拿来试试

oldbyte = -5

newbyte = (oldbyte >>> bitcount).toByte 的结果仍为-3,似乎没起作用

通过推测以及其他网友的经验,最后得知这其中的一个【坑】

上面表达式中oldbyte,在我的理解上是一个字节的位移操作,而实际上

编译器偷偷将oldbyte转为Int类型四字节进行位移运算的,即

-5  =  1111 1111 1111 1111 1111 1111 1111 1011

最左边第一位为符号位,>>>1 运算后变为 

          0111 1111 1111 1111 1111 1111 1111 1101   

.toByte 运算后取最低字节 1111 1101,这就是 -3

 

那么又该如何操作才能按字节进行无符号位移运算呢,答案是

newbyte = ( (oldbyte & 0xff) >> bitcount).toByte

oldbyte & 0xff运算,将高位三个字节都屏蔽掉,只保留低位一字节有效位

           0000 0000 0000 0000 0000 0000 1111 1011

也就是得到了四字节Int表示的oldbyte原字节值0xfb,然后再做普通右移操作

           0000 0000 0000 0000 0000 0000 0111 1101  

最后取低字节 .toByte,就是预期值 0111 1101 

 

参考:

https://blog.youkuaiyun.com/zxk1995/article/details/105838191

https://blog.youkuaiyun.com/qq_38006520/article/details/82667983?utm_medium=distribute.pc_relevant.none-task-blog-baidujs-1

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值