背景
做音频开发的同学一般会和byte数组打交道比较多,因为PCM原始数据一般都是byte数组来表示,如果音频的位深是16bit,那就会是连续两个byte元素表示一个音频幅值。如果需要对幅值进行计算,那就要先将两个byte还原回short值(16位数)再进行计算。
我的byte数组是小端存储,于是我想当然的认为short值计算的Java代码应该是:
//2个byte转化为1个short
//将高字节填充到short的高8位,低字节填充到short的低8位
short data = bytes[0] + (bytes[1] << 8);
复制代码
运行结果发现,在两个byte都是正数的情况下无问题,任一个是负数或者两个负数的情况下,会出现高8位数据减去了1的情况。比如:
0xb1 + (0x04 << 8) 会得到值 0x03b1,而不是 0x04b1
复制代码
原因
补码
学计算机组成原理的时候,相信大家都对“补码”一词有概念。这个问题正是补码引起的。
CPU里只有加法器(ALU),没有减法器,因为可以用补码将减法变为加法。
原码和补码的关系:
正数: 补码和原码一致
负数: 原码的符号位不变,其他位取反加1就是补码
如:
-1的原码(8bit) : 1000 0001
-1的补码(8bit) : 1111 1111 (即0xff)
所以,做个最简答的减法 1 - 1
得:1 - 1