在一个范围内包装无符号整数加法/减法

时间:2017-03-22 01:20:01

标签: c++ c algorithm

我需要一个计算unsigned valsigned dX之和的函数,并将结果包装在范围lowerupper

之内

例如:

5-6的更改以及010的范围将返回10

< 1 2 3 4 5 6 7 8 9 10 >

23的更改以及13的范围将返回2

/*
 * Given a value and a change in that value (dX), find the sum and wrap it between lower and upper.
 */
unsigned int wrap(unsigned int val, const int dX, const unsigned int lower, unsigned int upper)
{

}

我真的不知道如何处理无符号和带符号的加法/减法以避免下溢。我也不确定如何包装下限。

2 个答案:

答案 0 :(得分:2)

首先,计算上限 - 下限以用作模数值并转换为int(根据您的注释,上限 - 下限大于最大有符号整数值的情况不需要处理) :

int modulus = (int)(upper - lower) + 1;

然后你可以用模数模数dX,考虑到包裹:

dX %= modulus;

dX现在的值介于 - (模数-1)和模数-1之间。如果它是负的,只需加上模数:

if(dX < 0)
    dX += modulus;

dX现在保证是积极的,你只需处理溢出。您可以添加val和lower之间的差异,然后再次检查模数。这避免了必须处理无符号溢出。

dX += (val - lower);
if(dX >= modulus)
    dX -= modulus;

这为您提供了一个相对于下限的值,您可以使用它来计算新的val:

val = lower + (unsigned int)dX;

答案 1 :(得分:2)

如果您愿意将dxconst int更改为int,则可以循环执行算术。这可以避免upper - lower超过INT_MAX时可能出现的问题。

#include <stdio.h>

unsigned int wrap_add(unsigned int val,
                      int dx,
                      const unsigned int lower,
                      const unsigned int upper);

int main(void)
{
    printf("Range [0, 10]: 5 + (-6) = %u\n", wrap_add(5, -6, 0, 10));
    printf("Range [1, 3]: 2 + 3 = %u\n", wrap_add(2, 3, 1, 3));
    printf("Range [2, 5]: 2 + (-9) = %u\n", wrap_add(2, -9, 2, 5));

    return 0;
}

unsigned int wrap_add(unsigned int val,
                      int dx,
                      const unsigned int lower,
                      const unsigned int upper)
{
    while (dx < 0) {
        if (val == lower) {
            val = upper;
        } else {
            --val;
        }
        ++dx;
    }

    while (dx > 0) {
        if (val == upper) {
            val = lower;
        } else {
            ++val;
        }
        --dx;
    }

    return val;
}

节目输出:

Range [0, 10]: 5 + (-6) = 10
Range [1, 3]: 2 + 3 = 2
Range [2, 5]: 2 + (-9) = 5