用整数“四舍五入”

时间:2009-09-05 21:53:46

标签: c++ embedded

我正试图摆脱我职能中的花车。

我有一个函数操作16位整数值,这是一个升级的8位值。然后将缩减的8位发送到输出。

我确定我不是很好解释。像这样:

int8 spot_value = 21;  //arbitrary. just need a starting point
int16 running_value;

running_value = spot_value << 8;  //multiply by 256 which is 5376
running_value += 154;  //my upscaled value is now 5530
spot_value = running_value >> 8;  //downscale again

如果我们使用浮点数,我的缩减值将是21.6,我可以轻松地将其舍入到22并转换为int8。但是它会截断到21,这是我不想要的。

如果它是一个浮点数但是没有将任何东西转换成浮点数(甚至是暂时的),是否有一种方法可以“整数”整数整数?

这可能比我想要的要简单得多。

6 个答案:

答案 0 :(得分:8)

您可以为该值添加1/2。在你的缩放系统中,这是128。

int8 spot_value = 21;  //arbitrary. just need a starting point
int16 running_value;

running_value = spot_value << 8;  //multiply by 256 which is 5376
running_value += 154;  //my upscaled value is now 5530
spot_value = running_value + 128;  //add an additional 1/2 for rounding
spot_value = spot_value >> 8;  //downscale again

...或

scale_shift = 8;
scale = 1 << scale_shift
round = scale >> 1;

int8 spot_value = 21;  //arbitrary. just need a starting point
int16 running_value;

running_value = spot_value << scale_shift;  //multiply by 256 which is 5376
running_value += 154;  //my upscaled value is now 5530
spot_value = (running_value + round) >> scale_shift;  //downscale again
根据戴维的答案,还是一个小技巧......

running_value = spot_value << scale_shift;  //multiply by 256 which is 5376
running_value += 154;  //my upscaled value is now 5530
spot_value = (running_value >> 8) + ((running_value >> 7) & 1)

答案 1 :(得分:3)

在缩减之前,只需在值中添加一些内容即可。也就是说,当降档8时,添加128,它将导致舍入值。

对于一般情况,当缩小N位时,在缩小之前添加1 << (N-1)以获得舍入值。

答案 2 :(得分:3)

running_value = spot_value << 8;  //multiply by 256 which is 5376
running_value += 154;  //my upscaled value is now 5530
if(spot_value & (1 << 7)) {
    spot_value = (running_value >> 8) + 1;  //downscale again, but add 1 since the top bit of removed was set, i.e. ">= 1/2"
} else {
    spot_value = running_value >> 8; //downscale normally
}

答案 3 :(得分:2)

您应该检查一下您是否高于或等于running_value以上的0.5。即:

int16 round = (running_value >> 7) & 1; // =1 if decimal part >= 0.5, =0 otherwise.
spot_value = running_value >> 8 + round;  //downscale again

答案 4 :(得分:0)

我被烧伤的一件事

int8 spot_value = 21;  //arbitrary. just need a starting point
int16 running_value;

running_value = spot_value << 8;  //multiply by 256 which is 5376

你正在8位变量spot_value上做8的leftshift。您将值放在一个16位变量中,因此它应该可以正常工作。但是,如果将代码移植到新的微程序,或切换编译器,或更改优化,或将代码重构为内联等,则可能会无意中移出整个值。

基本上,它归结为不信任编译器。在嵌入式系统上,您没有gcc的健壮性。我通常使用累加器约定来补偿这个:

int8 spot_value = 21;  //arbitrary. just need a starting point
int16 running_value;

running_value = spot_value;  //load accumulator for multiply
running_value <<= 8;         //multiply accumulator (which is 21) by 256

同样的原理适用于乘法和除法,特别是在改变位宽时。

答案 5 :(得分:0)

注意,只是对未定义的有符号整数进行右移。左移是定义的。有三种可能的行为:

1)编译器将使用'sign-extension'并使用原始MSB的值填充空出的MSB(您提供的代码所需的行为)。

2)填充空位,零

3)用一个

填充空出的位

我认为可能但空位不可能是随机的。就个人而言,我从未观察过(1)以外的行为,但可能性存在,如果需要可移植性和稳健性,应予以考虑。

如前所述,使用*和/是一种解决方案。我已经观察到了许多编译器的生成代码,并且总是通过移位操作实现乘法或除以字面常数2的幂,如果在架构上它更有效;即使没有明确设置优化选项。