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

Kai*_*hen 8 c

我需要拿一个size_t volume并计算这个结果size_t:

size_t next = (volume * 8 + 3) / 5
Run Code Online (Sandbox Code Playgroud)

如果这个结果会溢出,size_t那么next应该为零.问题当然是volume * 8 + 3溢出,而整个结果适合于size_t.

目前我正在拆分最后4位volume并分别执行乘法,加法和除法.我的问题是:如果没有比这更大的类型,我能做得比目前为止做得更好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;
}
Run Code Online (Sandbox Code Playgroud)

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

gna*_*729 6

vol1 = volume % 5,vol2 = 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
Run Code Online (Sandbox Code Playgroud)

显然,如果结果不适合size_t,您将获得溢出,但如果计算中的任何位置存在溢出,则不会.由于你乘以8/5,如果溢出,结果将是大约0.6*音量<音量,所以你可以返回

return result < volume ? (size_t) -1 : result;
Run Code Online (Sandbox Code Playgroud)

这肯定比返回0更好.

  • @WouterVerhelst:你有没有引用(提示:你没有,它是完美定义的)? (4认同)