It is a problem from C++ primer fifth edition problem 3.26, I don't know the difference between them ? May be the second one can avoid overflow.
May be the second one can avoid overflow.
Exactly. There's no guarantee that beg+end
is representable; but in the second case the intermediate values, as well as the expected result, are no larger than end
, so there is no danger of overflow.
The second form can also be used for affine types like pointers and other random-access iterators, which can be subtracted to give a distance, but not added together.
In general case the both expressions are invalid. For example the first expression is invalid because there is no such operation as + for pointers or iterators. The second expression is invalid in case when non-random access iterators are used. For example when bidirectional iterators are used.
So the correct construction in C++ will look the following way
mid = std::next( beg, std::distance( beg, end ) / 2 );
If we consider the two lines in a more generic setting, not related to binary search, the following observations can be made:
You are correct that the problem the second form tries to avoid is overflow, attempting to represent a number that is larger than the maximum representable number.
There is no restriction on how large the individual numbers beg and end are, so potentially they can both be larger than half of the maximum representable number. Adding them means that the intermediate result (beg+end) can overflow.
The second solution seems to eliminate the risk of overflowing, but introduces another one. If the values are signed values, their difference can again overflow (or underflow, depending on their signs). Unsigned values have no problem.
There is another solution which you didn't post:
mid = beg/2 + end/2
This solves every problem with overflow and underflow, but introduces a new problem, of precision loss. If working with integer values, division by 2 can give a result off by 0.5, adding these together, means that mid can be off by 1:
mid = 3/2 + 5/2; // mid is 3, instead of the 4 expected
Working with floating point values has other precision problems.
Getting back to the problem at hand, the binary search, it's easy to see that beg and end are unsigned values, so the second solution will always give the correct result.
The answer is in the book:
"Because the iterator returned from end does not denote an element, it may not be incremented or dereferenced."
Graphically it makes sense as an asymmetric range, [begin, off-the-end) or half-open range.
From Accelerated C++, page 28, Koenig.
© 2022 - 2024 — McMap. All rights reserved.