You bring up an interesting point, Clyde. It's true that Mark's routine
yields -1 as the result of dividing -1 by 2. 8^( But that could be seen as
the desired result. 8^). It leaves an error of 1/2, but then that's true of
*every* odd number in the input.
Mark's routine also has the advantage of leaving the size of the output
bins the same. That is, there are *exactly* two input numbers which yield
any given output number. With your scheme, a result of -40H is given *only*
by an input of -80H, while a result of 0 is given by *three* inputs: -1, 0,
and 1.
I'm sure there are applications where either one of these algorithms is
more useful than the other! Integers are fun, eh wot??

> Clyde Smith-Stubbs <@spam@clydeKILLspamHITECH.COM.AU> writes:
> > There is just one slight problem with using shifts to divide -ve
> > numbers. To illustrate: what happens to -1 when you do this?
>
> It gets divided by two yielding -0.5.
> In integer representation there is no 2**-1 bit, so division by right shift
> truncates, effectively rounding down (toward negative infinity).
> -0.5 rounds to -1.
>
> Your proposed alternate code simply biases the result for negative numbers
> by 0.5, implementing round toward zero. It is not obvious to me that
> round toward zero is more "correct".
>
> I would be inclined to prefer IEEE-style round to even.
>
> If you really care about what happens to the 0.5, you should probably be
> using fixed-point representation.

Who said anything about IEEE or floating point? The numbers being dealt with
here are twos-complement integers. The problem with the original code was that
(-X)/2 != -(X/2) - and the code was put forward as perfoming a division by of
of a twos-complement number (apart from the fact that there's no exponent here,
IEEE floats are NOT stored in twos complement form - they use sign/magnitude).

The point is this; if you want to do a signed right shift, then the code is
fine; if you want to do a division, then it yields an incorrect
result for some -ve numbers. If your application only requires signed right
shift, then by all means use signed right shift; but don't promote it as a
general method of doing division.

> You bring up an interesting point, Clyde. It's true that Mark's routine
> yields -1 as the result of dividing -1 by 2. 8^( But that could be seen as
> the desired result. 8^). It leaves an error of 1/2, but then that's true of
> *every* odd number in the input.

My point was that an arithmetic shift is not equivalent to division where
negative numbers are concerned - any algorithm labelled division should preserve
the property that (-X)/2 == -(X/2) - and right shift does not.

Looking again at the subject of this thread, it seems likely that Mark only
needed a right shift, and did not intend to suggest that the code performed
a division as such. But he used the term "divide" in the body of the message.

> > numbers. To illustrate: what happens to -1 when you do this?
>
> It gets divided by two yielding -0.5.
> In integer representation there is no 2**-1 bit, so division by right shift
> truncates, effectively rounding down (toward negative infinity).
> -0.5 rounds to -1.

No. That is not truncation you're describing: what Clyde posted results
in truncation (-1/2 truncated results in zero).

> Your proposed alternate code simply biases the result for negative numbers
> by 0.5, implementing round toward zero. It is not obvious to me that
> round toward zero is more "correct".
>
> I would be inclined to prefer IEEE-style round to even.

De gustibus non est disputandum, but having -1 / 2 give a result of -1
will be surprising to anyone who's accustomed to integer division as
usually implented.

> If you really care about what happens to the 0.5, you should probably be
> using fixed-point representation.

>
> My point was that an arithmetic shift is not equivalent to division where
> negative numbers are concerned - any algorithm labelled division should
preserve
> the property that (-X)/2 == -(X/2) - and right shift does not.

Why is that property any more important than (X+2)/2 == (X/2)+1 ? Or
the property 0 <= X-2*(X/2) < 2? Most language specifications do not
mandate usage of either the "symetric" model or "uniform model" of
division. I think many, including C, mandate that

This is partially true; the ANSI C standard does allow that an
implementation may round a negative result down, rather than towards
zero, when using the / operator. This was, however, introduced solely to
avoid a gross slowdown on bizarre hardware. The committee wanted to make
integer division well-defined, but compromised by defining the div() and
ldiv() functions, which round towards zero. See the ANSI C Rationale,
section 3.3.5.

I think this had best be concluded by saying that a signed right shift
does implement an operation that can be labelled "division", but that
most people would be surprised by the result of (-1)/2 in this case. Where a
particular application can accept rounding towards negative infinity, use
of a right shift for signed division may be a fast solution.

> I think this had best be concluded by saying that a signed right shift
> does implement an operation that can be labelled "division", but that
> most people would be surprised by the result of (-1)/2 in this case. Where a
> particular application can accept rounding towards negative infinity, use
> of a right shift for signed division may be a fast solution.

You may prefer the round-toward-zero semantics; I for one have NEVER had a
situation in which they were desirable, and have frequently had cases where
I wished that the identity:

((a mod m)+b) mod m == (a+b) mod m

would hold for--most notably--all 0<=a<m, -m<b<m, but unfortunately the
round-to-zero semantics on many machines break this requiring me to use
constructs like:

a=(a+m+b) mod m

rather than

a=(a+b) mod m

which is simpler, faster, and more logical. The only case I know of in
which round-toward-zero semantics are desirable are when converting a
number into a displayable representation; even there, the normal first
step is to take the absolute value of a number after (optionally) output-
ting a plus or minus sign; delaying any rounding until after the abs-val
operation will ensure consistent behavior.