避免整数乘法后除法溢出
Avoiding overflow in integer multiplication followed by division
我有两个积分变量a
和b
和一个常数s
resp。d
。我需要计算(a*b)>>s
resp的值。a*b/d
。问题是,乘法运算可能会溢出,即使a*b/d
可以适合给定的整型,最终结果也不会正确。
如何有效地解决这个问题?直接的解决方案是将变量a
或b
展开为更大的整型,但可能没有更大的整型。有更好的方法来解决这个问题吗?
如果没有更大的类型,则需要找到一个大int风格的库,或者使用长乘法手动处理它。
例如,假设a
和b
是16位的。然后您可以将它们重写为a = (1<<8)*aH + aL
和b = (1<<8)*bH + bL
(其中所有单独的组件都是8位数字)。那么您就知道总体结果将是:
(a*b) = (1<<16)*aH*bH
+ (1<<8)*aH*bL
+ (1<<8)*aL*bH
+ aL*bL
这4个组件中的每一个都将适合16位寄存器。现在,你可以在每个单独的组件上执行右移,注意适当地处理进号。
我还没有详尽地测试过这个,但是您可以先做除法,然后考虑余数,而牺牲额外的操作吗?由于d
是2的幂,所以所有的除法都可以简化为位运算。
例如,始终假设a > b
(您希望先除较大的数字)。那么a * b / d
= ((a / d) * b) + (((a % d) * b) / d)
如果较大的类型只有64位,那么直接的解决方案很可能会产生高效的代码。在x86 cpu上,两个32位数字的任何乘法都会在另一个寄存器中造成溢出。因此,如果您的编译器理解这一点,它可以为Int64 result=(Int64)a*(Int64)b
生成高效的代码。
我在c#中遇到了同样的问题,编译器生成了相当好的代码。c++编译器通常比。net JIT生成更好的代码。
我建议将代码转换为较大的类型,然后检查生成的汇编代码,以检查它是否良好。
在某些情况下(历史上使用选定常量的LCG随机数生成器),对于a和d的某些值,可以执行您想要的操作。
这被称为施拉格方法。div。
- 'short int'持有的值溢出,但"自动"不会溢出?
- 使用动态分配的数组会导致代码分析发出虚假的C6386缓冲区溢出警告
- 大于65535的C++数组[size]引发不一致的溢出
- 为什么我在leetcode上收到AddressSanitizer:地址0x602000000058上的堆缓冲区溢出错误
- C++中无符号字符溢出
- 在除法中不需要四舍五入
- 在 leetcode 上提交解决方案时出现堆栈缓冲区溢出错误
- 我的 int main() 中出现堆栈溢出错误
- 整数溢出,最大值为 pow(10,19)
- 获取隐式转换溢出从无符号到已签名的警告
- 使用 strcat 获取缓冲区溢出错误
- 在TFHE(完全快速同态加密)上执行除法
- 使用 int 表示浮点除法 C++
- c++ 的除法的其余部分出现"堆栈溢出"异常
- 如何避免pow函数用数字除法时出现整数溢出
- 为什么我的长长溢出/变成负的整数除法
- 使用pow()进行除法溢出
- 做一个可能溢出的乘法然后用除法验证
- 整数除法溢出
- 避免整数乘法后除法溢出