为什么M= L+ ((R - L) /2)而不是M=(L+R)/2避免c++中的溢出
Why M = L + ((R - L) / 2) instead of M=(L+R)/2 avoid overflow in C++?
你好,我正在寻找问题的c++解决方案"假设一个排序数组在事先未知的某个枢轴上旋转。(例如,0 1 2 4 5 6 7可能变成4 5 6 7 0 1 2)你如何在旋转数组中有效地找到一个元素?您可以假设数组中不存在重复项。"
int rotated_binary_search(int A[], int N, int key) {
int L = 0;
int R = N - 1;
while (L <= R) {
// Avoid overflow, same as M=(L+R)/2
int M = L + ((R - L) / 2);
if (A[M] == key) return M;
// the bottom half is sorted
if (A[L] <= A[M]) {
if (A[L] <= key && key < A[M])
R = M - 1;
else
L = M + 1;
}
// the upper half is sorted
else {
if (A[M] < key && key <= A[R])
L = M + 1;
else
R = M - 1;
}
}
return -1;
}
看到评论说使用M= L+ ((R - L)/2而不是M=(L+R)/2可以避免溢出。为什么呢?提前谢谢
因为…
让我们暂时假设您正在使用无符号字符(当然也适用于更大的整数)。
如果L是100,R是200,第一个版本是:
M = (100 + 200) / 2 = 300 / 2 = 22
100+200溢出(因为最大的unsigned char是255),并且您得到100+200=44 (unsigned no。除了)。
另一方面,第二个:
M = 100 + (200-100) / 2 = 100 + 100 / 2 = 150
没有溢出。
正如@user2357112在评论中指出的那样,天下没有免费的午餐。如果L为负,则第二个版本可能无法工作,而第一个版本可以。
不确定,但如果int的最大限制是100。
R=80 & L = 40
then,
M=(L+R)/2
M=(120)/2, here 120 is out limits if our integer type, so this causes overflow
然而,M = L + ((R - L) / 2)
M = 80 +((40)/2)
M = 80 +20
M =100.
所以在这种情况下,我们不会遇到超出整型限制的值。因此,理论上,这种方法永远不会遇到溢出。
我希望这个比喻能有所帮助
这个注释是错误的,原因有很多。
- 对于特定的问题,溢出的风险可能为零。
- 重新排序计算并不保证编译器将按照该顺序执行。
- 如果存在排序可能导致溢出的值范围,则存在另一个重新排序计算将导致溢出的值范围。
- 如果溢出可能是一个问题,那么应该显式控制,而不是隐式控制。
这是一个非常适合断言的地方。在这种情况下,只有当N
小于int
的最大正范围的一半时,算法才有效,因此在断言中表示。
如果算法需要在signed int
的整个正范围内工作,则应在断言中明确测试该范围,并通过引入序列点(例如分为两个语句)对计算进行排序。
做好这件事很难。数值计算充满了这些东西。如果可能的话,最好避免。在没有做自己的研究之前,不要接受随机的建议(即使是这个!)。
在这个特定的实现中避免了溢出,保证L
和R
是非负的,L <= R
。在这些保证下,很明显R - L
不会溢出,L + ((R - L) / 2)
也不会溢出。
在一般情况下(即对于L
和R
的任意值),R - L
和L + R
一样容易溢出,这意味着这个技巧没有达到任何目的。
- C++避免重复声明的语法是什么
- 在没有太多条件句的情况下,我如何避免被零除
- 如何重构类层次结构以避免菱形问题
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 以下示例中如何避免代码复制?C++/库达
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 是否应该在模板化代码中完全避免const
- 我应该避免多重实现继承吗
- 为了方便起见,我应该避免公开私有字段变量吗
- 在为LINUX创建共享库时,如何避免STL的私有/弱副本
- 避免在C++中重复子类定义
- "Inverse SFINAE"避免模棱两可的过载
- 如何避免在仅标头库中C++类/变量重定义
- Python 集合.计数器,如何避免重复查找
- 是否应避免从非常量迭代器转换为常量迭代器?
- 避免矢量中的对象切片<Base><shared_ptr>
- 有没有办法在从编译器获取参数时避免预处理器宏?
- 如何避免LED在循环状态变化中闪烁?
- make 命令如何避免重新编译未更改的源文件?
- 避免碎片化的ClientHellos with OpenSSL (DTLS)