Integer division and negative numbers

| 7 Comments

I thought I understood basic arithmetic!

I've just learned that Ruby and Python (and, I'm told Tcl) define integer division of or by a negative number differently that C and Java do. Consider the quotient -7/3. Java gives -2. Ruby gives -3.

Modulo is different, too: In Java -7%3 is -1. But in Ruby it is 2.

I think I prefer the C and Java version of division, because it has the nice property that: -x/y = -(x/y). In general, this is not the case in Ruby.

On the other hand, Ruby's integer division can be explained with a simple rule. For the quotient q=x/y, we can say that q is the largest integer such that q*y<=x. For this rule, "largest" and "less than" have their obvious meanings: closest to positive infinity and closer to negative infinity. Maybe there is an equally succinct and general definition of integer division for C and Java, but it looks to me as if it requires special-casing the signs of the operands or defining "less than" as "closer to zero".

I haven't done much programming in Ruby or Python, but I suspect that this isn't the kind of thing that lis likely to cause bugs in practice. I don't know when I actually do integer division with negative operands. It reminds me, however of Josh Bloch's recent blog post and drives home his point that integer arithmetic is not as simple as it appears!

(Ruby and Python aficionados are invited to use the comments to explain why your language of choice does the right thing :-)

Update: comments are now closed. Comment spammers have found the entry

7 Comments

Ruby and python are probably just showing you more closely what hardware does (at least for powers of two). When you arithmetic shift right, on a 2's compliment number, you will get the value that python / ruby give you. For Example 1111 1101 (-3) /2 (a. shift right) will give you 1111 1110 (-2). If I had to guess this is either what hardware is doing or an attempt to mimic hardware. The only problem with this theory is that these languages are both implemented as interpretters in C, so unless the python / ruby is dynamically creating assembly and executing it (not what I would expect), I cant really see why it would be doing that rather than what C returns by default for devide and modulo.

LISP shows you the actual, correct value. When passed (/ -7 3) it returns to you the ratio -7/3. Also (truncate (/ -7 3)) returns to you both -2 and -1/3. Common Lisp provides both (mod -7 3) => 2,and (rem -7 3) => -1 .

From the language spec (http://www.lisp.org/HyperSpec/Body/fun_modcm_rem.html):

mod performs the operation floor on number and divisor and returns the remainder of the floor operation.

rem performs the operation truncate on number and divisor and returns the remainder of the truncate operation.

Cheers,
Russ

Perl does it like Ruby and Python do; unsurprisingly.

I don?t have a clear idea for which one is better. I?d rather pick one in terms of practical usefulness than theoretical argument, for which I?d have to go through a few actual programming problems in my head to decide which one I?d like better or what the tradeoffs are.

I think Java has it wrong -- at least if you take common math definitions as the standard. The behaviour of Java actually got me once -- fortunately I ran into the bug the mismatch of my expectations and what Java does quickly enough.

Here is my understanding of what it should be:

When running 'a mod b', 'a % b' or 'mod(a,b)' in a computer program I expect it to return the common residue (not the modulus, the modulus is actually the b itself). The common residue is defined as non-negative (see e.g. http://mathworld.wolfram.com/CommonResidue.html), so I expect the result of the function call to be non-negative.

Apart from having the easy rule you expressed in your post, it also means the residue function has a smaller range and the integer division changes in regular intervals (note that Java returns 0 as result of a/b for all values of a in [-b + 1, b -1], i.e. 2b - 1 values, instead of the usual b values). Way to irregular for my taste :-)

Cheers,
Peter

Hmm, actually, I was wrong.

Perl does NOT follow Python and Ruby. In fact, it really doesn't care much about integer math at all. You have to ask for it using the "integer" pragma, which enables integer-only math for most operators in the rest of the scope. The documentation for the pragma actually calls out the case of the modulus operator:

""Internally, native integer arithmetic (as provided by your C compiler) is used. This means that Perl's own semantics for arithmetic operations may not be preserved. One common source of trouble is the modulus of negative numbers, which Perl does one way, but your hardware may do another.""

Indeed, on my machine (Linux, x86, GCC 3.x), it produces the following:

$ perl -le'use integer; print -7/3; print -7%3'
-2
-1

Without the pragma, modulus says something else:

$ perl -le'use integer; print -7/3; print -7%3'
-2.33333333333333
2

This is what threw me off when I wrote the previous comment. So Perl generally wants you not to worry about floats vs ints, which means for all intents and purposes it does do it the way Ruby and Python do, except that you can explicitly ask it to it the way your C compiler does.

"The mod function is defined [mathematically] as the amount by which a number exceeds the largest integer multiple of the divisor that is not greater than that number." [1]

So, taking the example (-7 % 3), we see that the largest integer multiple of the divisor that is not greater than -7 is -9, and the amount by which -7 exceeds this number is 2. So Ruby and Perl get it right, for one definition of right.

In Perl, you can emulate C's behavior with the 'use integer' pragma. [2]

[1] http://mathforum.org/library/drmath/view/52343.html
[2] http://aspn.activestate.com/ASPN/Mail/Message/perl5-porters/1588298

Incidentally, this does have some uses. For example, here is one way to determine the day of the week on which the first day of the month falls, using Perl's gmtime:

# day of the month and zero-indexed week day
($d, $wd) = (gmtime(time))[3, 6];

# day of the week on which the month begins
$wd = ($wd - (($d % 7) - 1)) % 7;

For example, it is currently the 6th of June (CST), a Tuesday, which corresponds to the value 2, so we get

$wd = (2 - ((6 % 7) - 1)) % 7);

which is the same as

$wd = (-3 % 7) = 4;

And this corresponds to Thursday, which is in fact the day of the week on which June began.


Also, my first comment essentially repeated the following sentence, which I missed on my first reading: "On the other hand, Ruby's integer division can be explained with a simple rule. For the quotient q=x/y, we can say that q is the largest integer such that q*y<=x."

Sorry about that.

Books

Comprehensive coverage of Ruby 1.8 and 1.9

"The New Most Important Ruby Book"
Peter Cooper,
rubyinside.com

Completely updated for Ajax and Web 2.0

"A must-have reference"
Brendan Eich,
creator of JavaScript

The classic Java quick-reference

Advertising

Pages

Hosted By

Powered by Movable Type 4.21-en