这是一个问题来自C ++引言第五版问题3.26,我不知道它们之间的区别? 可能是第二个可以避免溢出。
答案 0 :(得分:15)
可能是第二个可以避免溢出。
完全。无法保证beg+end
可以表示;但在第二种情况下,中间值以及预期结果不大于end
,因此没有溢出的危险。
第二种形式也可用于仿射类型,如指针和其他随机访问迭代器,可以减去它们以给出距离,但不能一起添加。
答案 1 :(得分:1)
一般情况下,两个表达式都无效。例如,第一个表达式无效,因为对于指针或迭代器没有+操作。 如果使用非随机访问迭代器,则第二个表达式无效。例如,使用双向迭代器时。
因此,C ++中的正确构造将采用以下方式
mid = std::next( beg, std::distance( beg, end ) / 2 );
答案 2 :(得分:1)
如果我们在更通用的设置中考虑这两行,与二分搜索无关,可以进行以下观察:
你是对的,第二种形式试图避免的问题是溢出,试图表示一个大于最大可表示数字的数字。
对于个体数量的大小有多大没有限制,因此它们可能都大于最大可表示数量的一半。添加它们意味着中间结果(beg + end)可能溢出。
第二种解决方案似乎消除了溢出的风险,但又引入了另一种解决方案。如果值是有符号值,则它们的差异可能会再次溢出(或下溢,具体取决于它们的符号)。无符号值没有问题。
您还没有发布另一种解决方案:
mid = beg/2 + end/2
这解决了溢出和下溢的每个问题,但引入了一个精确丢失的新问题。如果使用整数值,除以2会使结果偏离0.5,将这些结果相加,意味着mid可以关闭1:
mid = 3/2 + 5/2; // mid is 3, instead of the 4 expected
使用浮点值还存在其他精度问题。
回到手头的问题,二进制搜索,很容易看到beg和end是无符号值,所以第二种解决方案总会给出正确的结果。
答案 3 :(得分:1)
答案在书中:
"因为从end返回的迭代器不表示元素,所以它可能 不得增加或解除引用。"
图形上它作为不对称范围是有意义的, [开始,非正式) 或半开放范围。
来自Accelerated C ++,第28页,Koenig。