Negative Integer Division Surprising Result

Negative integer division surprising result

For the actual values, i.e. 8.0/(-7.0), the result is roughly -1.143.

Your result using integer division is being rounded down toward the more negative value of -2. (This is also known as "Floor division")

This is why you will get the somewhat perplexing answers of:

>>> 8/(-7)
-2
>>> 8/7
1

Note: This is "fixed" in Python 3, where the result of 8/(-7) would be -1.143. So if you have no reason to be using Python 2, you should upgrade. ;)

In Python 3, if you still want integer division, you can use the // operator. This will give you the same answer as 8/(-7) would in Python 2.

Here's a Python Enhancement Proposal on the subject: PEP 238 -- Changing the Division Operator

Integer division in Python 3 - strange result with negative number

// is not integer division, but floor division:

7/-3  -> -2.33333...
7//-3 -> floor(7/-3) -> floor(-2.33333...) -> -3

PEP 238 on Changing the Division Operator:

The // operator will be available to request floor division unambiguously.

See also Why Python's Integer Division Floors (thanks to @eugene y) - Basically 7//-3 is -7//3, so you want to be able to write:

-7 = 3 * q + r

With q an integer (negative, positive or nul) and r an integer such that 0 <= r < 3. This only works if q = -3:

-7 = 3 * (-3) + 2

Integer division by negative number

Short answer: Language designers get to choose if their language will round towards zero, negative infinity, or positive infinity when doing integer division. Different languages have made different choices.

Long answer: The language authors of Python and Ruby both decided that rounding towards negative infinity makes more sense than rounding towards zero (like C does). The creator of python wrote a blog post about his reasoning here. I've excerpted much of it below.

I was asked (again) today to explain why integer division in Python returns the floor of the result instead of truncating towards zero like C.

For positive numbers, there's no surprise:

>>> 5//2
2

But if one of the operands is negative, the result is floored, i.e., rounded away from zero (towards negative infinity):

>>> -5//2
-3
>>> 5//-2
-3

This disturbs some people, but there is a good mathematical reason.
The integer division operation (//) and its sibling, the modulo
operation (%), go together and satisfy a nice mathematical
relationship (all variables are integers):

a/b = q with remainder r

such that

b*q + r = a and 0 <= r < b
(assuming a and b are >= 0).

If you want the relationship to extend for negative a (keeping b
positive), you have two choices: if you truncate q towards zero, r
will become negative, so that the invariant changes to 0 <= abs(r) <
otherwise, you can floor q towards negative infinity, and the
invariant remains 0 <= r < b. [update: fixed this para]

In mathematical number theory, mathematicians always prefer the latter
choice (see e.g. Wikipedia). For Python, I made the same choice
because there are some interesting applications of the modulo
operation where the sign of a is uninteresting. Consider taking a
POSIX timestamp (seconds since the start of 1970) and turning it into
the time of day. Since there are 24*3600 = 86400 seconds in a day,
this calculation is simply t % 86400. But if we were to express times
before 1970 using negative numbers, the "truncate towards zero" rule
would give a meaningless result! Using the floor rule it all works out
fine.

Floor division with negative number

The // operator explicitly floors the result. Quoting the Binary arithmetic operations documentation:

the result is that of mathematical division with the ‘floor’ function applied to the result.

Flooring is not the same thing as rounding to 0; flooring always moves to the lower integer value. See the math.floor() function:

Return the floor of x, the largest integer less than or equal to x.

For -6 // 4, first the result of -6 / 4 is calculated, so -1.5. Flooring then moves to the lower integer value, so -2.

If you want to round towards zero instead, you'll have to do so explicitly; you could do this with the int() function on true division:

>>> int(-6 / 4)
-1

int() removes the decimal portion, so always rounds towards zero instead.

python negative number divide the number than itself the result is always -1

In the remainder operation the python always takes the floor or the greatest integer function as the answer

why python int() works like this?

Try this:

>>> -1/2
-1
>>> -0.5
-0.5

The difference is that integer division (the former) results in an integer in some versions of Python, instead of a float like the second number is. You're using int on two different numbers, so you'll get different results. If you specify floats first, you'll see the difference disappear.

>>> -1.0/2.0
-0.5
>>> int(-1.0/2.0)
0
>>> int(-0.5)
0

What's the mathematical reason behind Python choosing to round integer division toward negative infinity?

But why Python // choose to round towards negative infinity?

I'm not sure if the reason why this choice was originally made is documented anywhere (although, for all I know, it could be explained in great length in some PEP somewhere), but we can certainly come up with various reasons why it makes sense.

One reason is simply that rounding towards negative (or positive!) infinity means that all numbers get rounded the same way, whereas rounding towards zero makes zero special. The mathematical way of saying this is that rounding down towards −∞ is translation invariant, i.e. it satisfies the equation:

round_down(x + k) == round_down(x) + k

for all real numbers x and all integers k. Rounding towards zero does not, since, for example:

round_to_zero(0.5 - 1) != round_to_zero(0.5) - 1

Of course, other arguments exist too, such as the argument you quote based on compatibility with (how we would like) the % operator (to behave) — more on that below.

Indeed, I would say the real question here is why Python's int() function is not defined to round floating point arguments towards negative infinity, so that m // n would equal int(m / n). (I suspect "historical reasons".) Then again, it's not that big of a deal, since Python does at least have math.floor() that does satisfy m // n == math.floor(m / n).



But I don't see C++ 's / not being compatible with the modulo function. In C++, (m/n)*n + m%n == m also applies.

True, but retaining that identity while having / round towards zero requires defining % in an awkward way for negative numbers. In particular, we lose both of the following useful mathematical properties of Python's %:

  1. 0 <= m % n < n for all m and all positive n; and
  2. (m + k * n) % n == m % n for all integers m, n and k.

These properties are useful because one of the main uses of % is "wrapping around" a number m to a limited range of length n.


For example, let's say we're trying to calculate directions: let's say heading is our current compass heading in degrees (counted clockwise from due north, with 0 <= heading < 360) and that we want to calculate our new heading after turning angle degrees (where angle > 0 if we turn clockwise, or angle < 0 if we turn counterclockwise). Using Python's % operator, we can calculate our new heading simply as:

heading = (heading + angle) % 360

and this will simply work in all cases.

However, if we try to to use this formula in C++, with its different rounding rules and correspondingly different % operator, we'll find that the wrap-around doesn't always work as expected! For example, if we start facing northwest (heading = 315) and turn 90° clockwise (angle = 90), we'll indeed end up facing northeast (heading = 45). But if then try to turn back 90° counterclockwise (angle = -90), with C++'s % operator we won't end up back at heading = 315 as expected, but instead at heading = -45!

To get the correct wrap-around behavior using the C++ % operator, we'll instead need to write the formula as something like:

heading = (heading + angle) % 360;
if (heading < 0) heading += 360;

or as:

heading = ((heading + angle) % 360) + 360) % 360;

(The simpler formula heading = (heading + angle + 360) % 360 will only work if we can always guarantee that heading + angle >= -360.)

This is the price you pay for having a non-translation-invariant rounding rule for division, and consequently a non-translation-invariant % operator.



Related Topics



Leave a reply



Submit