Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why does integer division round down in many scripting languages?

In the languages I have tested, - (x div y ) is not equal to -x div y; I have tested // in Python, / in Ruby, div in Perl 6; C has a similar behavior.

That behavior is usually according to spec, since div is usually defined as the rounding down of the result of the division, however it does not make a lot of sense from the arithmetic point of view, since it makes div behave in a different way depending on the sign, and it causes confusion such as this post on how it is done in Python.

Is there some specific rationale behind this design decision, or is just div defined that way from scratch? Apparently Guido van Rossum uses a coherency argument in a blog post that explains how it is done in Python, but you can have coherency also if you choose to round up.

(Inspired by this question by PMurias in the #perl6 IRC channel)

like image 807
jjmerelo Avatar asked May 20 '18 09:05

jjmerelo


People also ask

Why does integer division round down?

If the divisor and dividend have the same sign then the result is zero or positive. If the divisor and dividend have opposite signs then the result is zero or negative. If the division is inexact then the quotient is rounded towards zero. That is, up if it is negative, and down if it is positive.

What is integer division in programming?

The % (integer divide) operator divides two numbers and returns the integer part of the result. The result returned is defined to be that which would result from repeatedly subtracting the divisor from the dividend while the dividend is larger than the divisor.

Does integer division round or truncate?

Yes, the result is always truncated towards zero. It will round towards the smallest absolute value.


2 Answers

Ideally, we would like to have two operations div and mod, satisfying, for each b>0:

  1. (a div b) * b + (a mod b) = a
  2. 0 <= (a mod b) < b
  3. (-a) div b = -(a div b)

This is, however, a mathematical impossibility. If all the above were true, we would have

1 div 2 = 0 1 mod 2 = 1 

since this is the unique integer solution to (1) and (2). Hence, we would also have, by (3),

0 = -0 = -(1 div 2) = (-1) div 2 

which, by (1), implies

-1 = ((-1) div 2) * 2 + ((-1) mod 2) = 0 * 2 + ((-1) mod 2) = (-1) mod 2 

making (-1) mod 2 < 0 which contradicts (2).

Hence, we need to give up some property among (1), (2), and (3).

Some programming languages give up (3), and make div round down (Python, Ruby).

In some (rare) cases the language offers multiple division operators. For instance, in Haskell we have div,mod satisfying only (1) and (2), similarly to Python, and we also have quot,rem satisfying only (1) and (3). The latter pair of operators rounds division towards zero, at the price of returning negative remainders, e.g., we have (-1) `quot` 2 = 0 and (-1) `rem` 2 = (-1).

C# also gives up (2), and allows % to return a negative remainder. Coherently, integer division rounds towards zero. Java, Scala, Pascal, and C, starting from C99, also adopt this strategy.

like image 154
chi Avatar answered Sep 28 '22 03:09

chi


Floating-point operations are defined by IEEE754 with numeric applications in mind and, by default, round to the nearest representable value in a very strictly-defined manner.

Integer operations in computers are not defined by general international standards. The operations granted by languages (especially those of the C family) tend to follow whatever the underlying computer provides. Some languages define certain operations more robustly than others, but to avoid excessively difficult or slow implementations on the available (and popular) computers of their time, will choose a definition that follows its behaviour quite closely.

For this reason, integer operations tend to wrap around on overflow (for addition, multiplication, and shifting-left), and round towards negative infinity when producing an inexact result (for division, and shifting-right). Both of these are simple truncation at their respective end of the integer in two's-complement binary arithmetic; the simplest way to handle a corner-case.

Other answers discuss the relationship with the remainder or modulus operator that a language might provide alongside division. Unfortunately they have it backwards. Remainder depends on the definition of division, not the other way around, while modulus can be defined independently of division - if both arguments happen to be positive and division rounds down, they work out to be the same, so people rarely notice.

Most modern languages provide either a remainder operator or a modulus operator, rarely both. A library function may provide the other operation for people who care about the difference, which is that remainder retains the sign of the dividend, while modulus retains the sign of the divisor.

like image 33
Chromatix Avatar answered Sep 28 '22 05:09

Chromatix