有没有更好的计算方法(n * 8 + 3)/ 5?

时间:2015-06-26 15:52:56

标签: c

我需要size_t volume并在size_t

中计算此结果
size_t next = (volume * 8 + 3) / 5

如果此结果会溢出size_t,则next应为零。问题当然是volume * 8 + 3可能会溢出,而整个结果都适合size_t

目前我正在分割volume的最后4位并分别执行乘法,加法和除法。我的问题是:如果没有大于size_t的类型,我能比目前做得更好吗?

size_t next_volume(size_t volume) {
  // check if the numerator will overflow size_t
  if (volume > (SIZE_MAX - 3) / 8) {
    size_t lower, upper;

    // multiply lower 4 bits by 8 and add 3
    lower = ((volume & 0xF) * 8) + 3;
    // downshift the rest and multiply by 8
    upper = (volume >> 4) * 8;

    // divide upper remainder and lower by 5
    lower = ((upper % 5 << 4) + lower) / 5;

    // divide upper by 5
    upper = upper / 5;

    // ensure the sum will not overflow size_t
    if (upper + (lower >> 4) > SIZE_MAX >> 4)
      return 0;

    return (upper << 4) + lower;
  } else return (volume * 8 + 3) / 5;
}

该代码可能存在一些错误。我还没有通过广泛的测试,但我相信所有的主要想法都存在。

1 个答案:

答案 0 :(得分:6)

vol1 = volume % 5vol2 = volume - vol1。 vol2可以被5整除,因此在数学上(vol2 * 8)/ 5 =(vol2 / 5)* 8,所以你得到了正确的结果

size_t vol1 = volume % 5;
size_t vol2 = volume - vol1;
size_t result = (vol2 / 5) * 8 + (vol1 * 8 + 3) / 5

如果结果不适合size_t,显然会出现溢出,但如果计算中的任何地方出现溢出,则不会出现溢出。由于你乘以8/5,在溢出的情况下,结果将是大约0.6 *体积<1。音量,所以你可以返回

return result < volume ? (size_t) -1 : result;

肯定比返回0好。