假设我有两个无符号字节b
和x
。我需要将bsub
计算为b - x
,将badd
计算为b + x
。但是,我不希望在这些操作过程中发生下溢/溢出。例如(伪代码):
b = 3; x = 5;
bsub = b - x; // bsub must be 0, not 254
和
b = 250; x = 10;
badd = b + x; // badd must be 255, not 4
最明显的方法包括分支:
bsub = b - min(b, x);
badd = b + min(255 - b, x);
我只是想知道是否有更好的方法来做到这一点,即通过一些老生常谈的比特操作?
发布于 2015-11-02 16:17:37
文章Branchfree Saturating Arithmetic提供了实现这一点的策略:
他们的加法解决方案如下:
u32b sat_addu32b(u32b x, u32b y)
{
u32b res = x + y;
res |= -(res < x);
return res;
}
针对uint8_t进行了修改:
uint8_t sat_addu8b(uint8_t x, uint8_t y)
{
uint8_t res = x + y;
res |= -(res < x);
return res;
}
他们的减法解决方案是:
u32b sat_subu32b(u32b x, u32b y)
{
u32b res = x - y;
res &= -(res <= x);
return res;
}
针对uint8_t进行了修改:
uint8_t sat_subu8b(uint8_t x, uint8_t y)
{
uint8_t res = x - y;
res &= -(res <= x);
return res;
}
发布于 2015-11-02 15:50:29
一种简单的方法是检测溢出并相应地重置该值,如下所示
bsub = b - x;
if (bsub > b)
{
bsub = 0;
}
badd = b + x;
if (badd < b)
{
badd = 255;
}
在使用-O2编译时,GCC可以将溢出检查优化为条件赋值。
我测量了与其他解决方案相比的优化程度。在我的PC上进行1000000000+操作时,这个解决方案和@ShafikYaghmour的平均时间为4.2秒,而@chux的平均时间为4.8秒。这种解决方案也更具可读性。
发布于 2015-11-03 06:40:19
如果您使用的是足够新的版本,那么您可以使用built-ins来检测溢出。
if (__builtin_add_overflow(a,b,&c))
{
c = UINT_MAX;
}
https://stackoverflow.com/questions/33481295
复制相似问题