做一个可能溢出的乘法然后用除法验证
Any problems doing a multiplication with potential overflow and then verifying with division?
假设我有两个size_t
变量,我需要将它们相乘并得到size_t
的结果。
size_t first = ...;
size_t second = ...;
size_t result = first * second;
它们可能溢出,所以我需要检查一下。
"干净"的方法是首先使用除法检查乘法是否可行:
if( second != 0 && first > ((size_t)-1) / second ) {
//handle overflow
}
//proceed with computing first * second
看起来不那么"干净"的方法是先乘,然后用除法检查结果:
size_t result = first * second;
if( second != 0 && result / second != first )
//handle overflow
}
然而,由于无符号数的乘法通过在零周围包装而"安全溢出",这工作得很好,看起来就像以前的代码(先检查,然后相乘)。
第二个代码有什么潜在的问题吗?它会永远和第一个一样好吗?
我想说的是,你不仅需要检查除数,还应该检查余数:
if( second != 0 && (result / second != first || (result % second) != 0))
如果c=b*a,则c只有一个值,如c/b=a。尝试用任何其他值除以b都不会得到a。
但这不是整数数学,而是真正的数学。由于整数除法取四舍五入,因此该公式在技术上不成立,因为,假设b至少为2,(c+1)/b对于c的某些值也将是a。
从一个数学POV, 如果
((a*b) mod (2^n)) / b == a
对于某些溢出值为真(这意味着a和b都不为0),那么这是一个问题。
根据Wolfram Alpha的说法,溢出永远不会成立,因为为了得到一个结果,比特长度
结果变量n的值必须大于a*b (log[2](a*b)
)所需的位长。
代码方面,我现在也想不出任何问题
您上面指出的第一个方法绝对是不正确的。如上所述,将负数强制转换为无符号类型是不正确的,并且会导致未定义行为。
第二种方法,作为一个乘积可以不同于两个因子的乘法的唯一方法是在中间有一个溢出,将是正确的,但是再次,溢出可以处理未定义的行为,因此,将是不正确的(您隐含地认为溢出将由乘法模操作产生,结果确实是未定义的)。
检查可能溢出的一种方法是:
if (MAX_UINT / one_of_the_factors < the_other_factor) ...
这是完全定义的,允许您以可移植的方式在执行实际乘法之前检测溢出。
相关文章:
- lambda参数转换为constexpr技巧,然后获取带链接的数组
- 正在尝试了解输入验证循环
- 如何声明特征矩阵,然后通过嵌套循环初始化它
- 如何在C++中检查2D数组中负值的输入验证
- 这是我尝试让用户将值输入到数组中.然后将其隐藏为大量的星号
- boost::asio如何生成多个协同程序,然后加入它们
- LibGit2 SSH身份验证失败
- 如何将图像传输到c++(dll)中的缓冲区,然后在c#的缓冲区中读/写
- Vulkan验证层不断在VkQueuePresentKHR()上抛出图像布局错误
- 在std::thread中,joinable()然后join()线程安全吗
- constexpr上下文中std::initializer_list的验证
- 正在验证c++中用户的整数输入
- C++:如何读取分离变量,然后读取向量
- 加密++验证大文件签名
- C++卡验证问题
- 为什么我的递归函数按降序打印,然后按升序打印?
- C - 布尔值返回值,然后验证它
- 在数组中输入5个元素,检查验证,然后输出C++
- 如何写入文件,然后将其读回以验证其内容,确保您获得的是磁盘上的内容而不是缓存
- 做一个可能溢出的乘法然后用除法验证