Skip to main content

Go round.. but which way?

It all started with Kushal's query about python's strange behavior regarding % operator. But my own digging went on so much that I got tempted to write an entire post than just a reply. Kushal, you might find the answer for your query somewhere at the end.

Integer division is far more interesting than one could imagine. Especially when it comes to negative numbers. Even more interesting are the topics of remainder, modulo and truncation. In general, for given two integers N and D, you would simply divide the absolute values |N| by |D| and if only one of them carries negative sign you would mark the quotient negative otherwise positive, the remainder would carry the sign of N. Now take an example,
-2/3. Your quotient would be 0 and remainder would be -2. Now try the same thing on Python. You will get
-2/3 = -1 and -2%3 = 1.
Now lets rethink of both manual and python's results.
Your manual quotient is zero because the absolute value of N is less than that of D. But thinking in terms of absolute values is just a convenient method and not the fundamental operation of division. So what is it? Can we take 3 zero times so that we will be left with -2? Is it at all correct to get a negative remainder while the portion you have chosen to divide with is positive?

And what does python does to get this apparently incorrect result? In literal sense it takes away 3 one time from -2 and you are left with 1. It could actually take 3 any number of times and the remainder would change respectively. But in most of those cases, the remainder would be greater in its absolute value than 3, so lets discard them all. But the remainder -2 and +1 are both indivisible and lesser in absolute value than three. So what decides which way is the correct one?
Things might get even complicated in practical sense with negative divisors.

Now consider the rational division which is approximately -0.6666. Thus computationally you can round it to -1. But consider -1/3. Here the rational division is -0.3333. But still, python gives the result as -1. So which way is python rounding the numbers when it comes to division? Lets take 2/3, python gives 2/3=0, which is the correct quotient. But the exact division is 0.6666 which could be rounded up to 1 rather than 0. Actually there are various ways you can truncate a given number to an integer,
1. towards the nearest integer,
2. towards zero
3. away from zero
4. round up i.e. always to the greater integer
5. and finally round down i.e. always towards lesser integer.

Manually we chose the option #2. But Python in case of division is observed to be always rounding DOWN. That is why a positive 0.6666 is rounded down to 0 and negative -0.6666 is rounded further down to -1 and not 0. This works for positive integers, but does it for negatives as well? Shouldn't it be towards zero when it comes to integer division? This is probably the reason why python behaves differently for negative number's division and modulo(%). A general formula to calculate remainder is:

rem(N,D) = N - (N/D)*D

So, assuming rounding down as python does(i.e. -2/3 = -1), the remainder for -2/3 this way comes out to be 1.
If you consider rounding up, or the manual calculation (i.e. -2/3 = 0), the remainder comes out to be -2.

So which one is correct? Lets examine few tests from maths itself.
One rule says,
(-N)/D = N/(-D) = - (N/D)

This is where python fails. Because -2/3= -1 while -(2/3) = 0.
But there is one case where python would give you the correct practical answer with the same computations. Lets first see how do we use mod functions in real life. Assume the current time in a 12 hour clock to be 9:00. You want to see what will it show after 4 hours?
So you do 9+4 which is 13 and then take the modulo 12 of this i.e. (9+4)%12=1 i.e. the remainder when you divide 13 by 12.

The same way if you want to know what time it was 10 hours back you would do:

(9-10) % 12
= -1 % 12

Going by normal way of division and remainder, you find out -1/12=0 and the remainder is -1. But which 12hr practical clock will ever show you the time to be -1? None.

Now lets do it python way. You take the division -1/12=-1 (i.e. rounding down to -1), thus according to above mentioned formula the remainder is:

-1 - (-1/12) * 12 = -1 - (-1) *12 = -1 + 12 =11

Practically 10 hours before 9 is also always 11. So python is correct here giving (9-10)%12= 11. Hurray :-)

Now one more fundamental question, is modulo, which is generally what we call the % operator, the same number as the remainder in division or not? Answer is No. After looking around for the difference between remainder and modulo, I found this: http://mathforum.org/library/drmath/view/52343.html
Scroll down on the above page to get the table that illustrates different values of rem and mod functions. Now you would know that the analysis in this post is partly based on the above reference.

So finally whats the conclusion? About maths, I still could not find an affirmative source that would deny the condition (-N)/D=N/(-D)=-(N/D) and use of absolute values. So most probably python is wrong about the division, but its still only a doubt.

When it comes to modulo operator %, Python lives up to its name, i.e. modulo and returns the correct value instead of the mere remainder. This might be an effect of the probable inaccuracy in division. But its hard to imagine if it was unintentional. Specially since its different from C which leaves the confusion up to the compiler which in most cases follows the other way of correct quotient and wrong modulo. So the developers of python must be aware about this. It would be really nice if some of them could explain their own intentions and solve this riddle.

Comments

  1. Anonymous9:04 PM

    Got a problem with your general formula to calculate remainders. You state that it is rem(N,D)= N-(N/D*D.) My problem is, that(N/D)*D=N AND N-N would equal 0 which would make any result 0.

    ReplyDelete
  2. In the expression (N/D) we are not considering complete division with decimal point values, but this is only an integer division, thus (N/D)*D need not be equal to N.

    [P.S. Would be good if a contact/identity is left behind so that I could get in touch personally :) ]

    ReplyDelete
  3. hi,
    I'm studying GCSE level computing using python. I need to round random.randint/5 numbers down to integer values, can you explain a method in doing this,
    thank you
    Sanaa

    ReplyDelete

Post a Comment

Popular posts from this blog

Unicode 5.1 release and Indic changes

Unicode 5.1 release was announced earlier this month on 4th April. Here I have put a diff taken of Unicode 5.1 character database against that of Unicode 5.0. My buddy, Parag also did a nice job of summarizing the Indic specific changes, that I am trying to restate now. So, here go the updates on Indian scripts UCD: A. New Indic Scripts Added to Unicode: 1. LEPCHA: Lepcha is a language spoken by the Lepcha people in Sikkim in India,and parts of Nepal and Bhutan. The Lepcha script (also known as "róng") is a syllabic script which has a lot of special marks and requires ligatures. Its genealogy is unclear. Early Lepcha manuscripts were written vertically, a sign of Chinese influence. Lepcha is considered to be one of the aboriginal languages of the area in which it is spoken. Total number of speakers numbers near 50,000. Unicode Range =>U1C00 to U1C4F Chart URL => http://www.unicode.org/charts/PDF/U1C00.pdf 2. OL-CHIKI: The Ol Chiki script, also known

PVR is so wierd!

Yesterday we went second time to a mall bit far from office to complete the earlier failed mission of watching this 3D movie, Clash of the Titans. On ticket counter, we were first told that evening show was house full. Then we asked for a night show, and were told there isn't any show then and the gentleman handed us the pamphlet of all movie schedules. We checked on the nearby digital kiosk and also on the printed schedule to be sure of the show timings. Then went to second counter, and asked the lady for the night show tickets, and without any problem got the tickets for back seats. In fact this show was hardly 20% full, wonder how the evening show became houseful. But the biggest wonder/blunder is yet to come. On the entrance we were stopped for having a laptop bag along with (we had went straight after the office). In spite of having checked the bag, we were not allowed, because laptops were not allowed inside! Then we asked for keeping it at the baggage counter. But then, the

What is so wrong with Bhagwad Geeta?

Here's a discussion I had with someone over Bhagwad Geeta on TOI forum (Stop reading now if you don't want to go to the end, it may mislead): mukunda (Bengaluru) replies to Siddharth 21 Jul, 2011 02:50 PM Ok,lets read ch 4 verse 13. catur-varnyam maya srstam guna-karma-vibhagasah tasya kartaram api mam viddhy akartaram avyayam "According to the three modes of material nature and the work associated with them, the four divisions of human society are created by Me. And although I am the creator of this system, you should know that I am yet the nondoer, being unchangeable." 1st line"catur-varnyam maya srstam" 4 varnas are created by Me(Paramatma),2nd line "guna-karma-vibhagasah" where the vabhajan\categorization is based on one's guna composition and karma composition. 3rd and 4th line states how He is the non doer and unchangable. Sri Krishna says that each living entity is categorized into one of the 4 varnas based ONLY on their pre