我正在研究一种声音转换算法,其中接收到一系列签名短裤。
在算法的给定点,它将样本从 16 位转换为 14 位,它是这样进行的:
int16_t sample = (old_sample + 2) >> 2;
对我来说,很明显需要进行移位,因为我们想要摆脱至少 2 个有效位,但是+2
那里呢?
向下移动会丢失最低有效的两位。如果您只是移位,那么即使底部两位都已设置,它也将始终向下舍入。如果设置了较大的丢失位,则将 2 轮向上添加。
(另外值得注意的是,减少比特数的更好方法是使用抖动,即在减少样本大小之前添加随机(并且非常小)量的噪声;这避免了由于声音是周期性的问题,对于特定频率,舍入通常最终会持续上升或持续下降,从而导致声音出现明显的失真。链接的维基百科文章比我能更好地解释它!)
正如其他人所指出的,+2 是试图使右移执行四舍五入到最近的除法。但是,有两个问题:
32766 或 32767 的输入样本在int
添加 2 时可能会溢出(int
仅保证能够表示最多 32767 的数字);
负数右移的行为是实现定义的。
为了避免这些问题,应该是:
int16_t sample = (old_sample > 0 ? old_sample + 2L : old_sample - 2L) / 4;
(与移位运算符不同,C99 中的除法运算符被定义为向零舍入)。
我猜它打算有四舍五入的效果?我只是希望他们考虑到的情况old_sample
超过MAX_INT16 - 2
. 否则溢出时可能会出现问题。
如其他回复中所示,该代码的意图可能是四舍五入。但这肯定是一个非常糟糕的例子。这里发生了两件事,最初的程序员可能并不打算这样做:
int
和重新分配到int16_t
signed
值的右移提升到int
(因为+2
which 只是一个int
)在这里很糟糕,因为您不知道int
您碰巧登陆的任何随机平台上的精度是多少。
如果值为负,则值的右移signed
取决于编译器,因此结果也可能因平台而异。