Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In C# integer arithmetic, does a/b/c always equal a/(b*c)?

Let a, b and c be non-large positive integers. Does a/b/c always equal a/(b * c) with C# integer arithmetic? For me, in C# it looks like:

int a = 5126, b = 76, c = 14;
int x1 = a / b / c;
int x2 = a / (b * c);

So my question is: does x1 == x2 for all a, b and c?

like image 441
Jason Crease Avatar asked May 30 '13 13:05

Jason Crease


People also ask

What does << mean in C?

<< is the left shift operator. It is shifting the number 1 to the left 0 bits, which is equivalent to the number 1 .

What does %d do in C?

%d is a format specifier, used in C Language. Now a format specifier is indicated by a % (percentage symbol) before the letter describing it. In simple words, a format specifier tells us the type of data to store and print. Now, %d represents the signed decimal integer.


3 Answers

I liked this question so much I made it the subject of my blog on June 4th, 2013. Thanks for the great question!


Large cases are easy to come by. For example:

a = 1073741823; 
b = 134217727;
c = 134217727;

because b * c overflows to a negative number.

I would add to that the fact that in checked arithmetic, the difference between a / (b * c) and (a / b) / c can be the difference between a program that works and a program that crashes. If the product of b and c overflows the bounds of an integer then the former will crash in a checked context.

For small positive integers, say, small enough to fit into a short, the identity should be maintained.


Timothy Shields just posted a proof; I present here an alternative proof. Assume all the numbers here are non-negative integers and none of the operations overflow.

Integer division of x / y finds the value q such that q * y + r == x, where 0 <= r < y.

So the division a / (b * c) finds the value q1 such that

q1 * b * c + r1 == a

where 0 <= r1 < b * c

the division ( a / b ) / c first finds the value qt such that

qt * b + r3 == a

and then finds the value q2 such that

q2 * c + r2 == qt

So substitute that in for qt and we get:

q2 * b * c + b * r2 + r3 == a

where 0 <= r2 < c and 0 <= r3 < b.

Two things equal to the same are equal to each other, so we have

q1 * b * c + r1 == q2 * b * c + b * r2 + r3

Suppose q1 == q2 + x for some integer x. Substitute that in and solve for x:

q2 * b * c + x * b * c + r1 = q2 * b * c + b * r2 + r3
x  = (b * r2 + r3 - r1) / (b * c)

where

 0 <= r1 < b * c
 0 <= r2 < c
 0 <= r3 < b

Can x be greater than zero? No. We have the inequalities:

 b * r2 + r3 - r1 <= b * r2 + r3 <= b * (c - 1) + r3 < b * (c - 1) + b == b * c

So the numerator of that fraction is always smaller than b * c, so x cannot be greater than zero.

Can x be less than zero? No, by similar argument, left to the reader.

Therefore integer x is zero, and therefore q1 == q2.

like image 154
Eric Lippert Avatar answered Oct 25 '22 12:10

Eric Lippert


Let \ denote integer division (the C# / operator between two ints) and let / denote usual math division. Then, if x,y,z are positive integers and we are ignoring overflow,

(x \ y) \ z
    = floor(floor(x / y) / z)      [1]
    = floor((x / y) / z)           [2]
    = floor(x / (y * z))
    = x \ (y * z)

where

a \ b = floor(a / b)

The jump from line [1] to line [2] above is explained as follows. Suppose you have two integers a and b and a fractional number f in the range [0, 1). It is straightforward to see that

floor(a / b) = floor((a + f) / b)  [3]

If in line [1] you identify a = floor(x / y), f = (x / y) - floor(x / y), and b = z, then [3] implies that [1] and [2] are equal.

You can generalize this proof to negative integers (still ignoring overflow), but I'll leave that to the reader to keep the point simple.


On the issue of overflow - see Eric Lippert's answer for a good explanation! He also takes a much more rigorous approach in his blog post and answer, something you should look into if you feel I'm being too hand-wavy.

like image 70
Timothy Shields Avatar answered Oct 25 '22 12:10

Timothy Shields


If the absolute values of b and c are below about sqrt(2^31) (approx. 46 300), so that b * c will never overflow, the values will always match. If b * c overflows, then an error can be thrown in a checked context, or you can get an incorrect value in an unchecked context.

like image 4
Tim S. Avatar answered Oct 25 '22 10:10

Tim S.