我需要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;
}
该代码可能存在一些错误。我还没有通过广泛的测试,但我相信所有的主要想法都存在。
答案 0 :(得分: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
如果结果不适合size_t,显然会出现溢出,但如果计算中的任何地方出现溢出,则不会出现溢出。由于你乘以8/5,在溢出的情况下,结果将是大约0.6 *体积<1。音量,所以你可以返回
return result < volume ? (size_t) -1 : result;
肯定比返回0好。