Python signed multiplication is not commutative near floor division?

91 Views Asked by At
-1 * abs(-123)//10

is

-13

but

abs(-123)//10 * -1

is

-12

Why is this? What's the rule to be consistent and predictable when coding this?

4

There are 4 best solutions below

0
Zein On

Because the first operation does -1 * abs(-123) then does integer division. Integer division always rounds towards -Inf and not zero. so the first one is actually -123//10 = -13 and the second is -(123//10) = -(12) = -12

0
Samathingamajig On

// is the floored division operator in Python. Since it's not standard division, the order matters.

-1 * abs(-123)//10

becomes

floor(((-1) * abs(-123)) / 10)
floor((-1 * 123) / 10)
floor(-123 / 10)
floor(-12.3)
-13

and

abs(-123)//10 * -1

becomes

floor(abs(-123) / 10) * (-1)
floor(123 / 10) * -1
floor(12.3) * -1
12 * -1
-12

as you can see, these become completely different expressions because in one of them, the negation happens before the flooring, while the second has the negation happen afterwards. The floor function always rounds down (except when it's already an integer), and -13 is more "down" than -12.

There's a similar function called trunc (short for truncate) which will get rid of the decimal point, effectively rounding down for positive numbers and rounding up for negative numbers.

import math
math.trunc(-1 * abs(-123) / 10)

and

import math
math.trunc(abs(-123) / 10) * -1

Both of these become -12

import math
math.trunc(-1 * abs(-123) / 10)
math.trunc(-1 * 123 / 10)
math.trunc(-123 / 10)
math.trunc(-12.3)
-12
import math
math.trunc(abs(-123) / 10) * -1
math.trunc(123 / 10) * -1
math.trunc(12.3) * -1
12 * -1
-12
0
slothrop On

The key facts are:

  1. Integer division always rounds down - with "down" meaning "less positive" or "more negative". In the words of the documentation, rounding is "towards minus infinity" (not 'towards zero')

  2. The * and // operators have equal precedence. So where both are used, the order is left-to-right.

So:

-1 * abs(-123)//10 = -1 * 123 // 10 = (-1 * 123) // 10 = -123 // 10 = -13 (i.e. -12.3, rounded towards minus infinity)

and

abs(-123)//10 * -1 = 123 // 10 * -1 = (123 // 10) * -1 = 12 * -1 (rounding 12.3 towards minus infinity) = -12

0
JakuWorksOfficial On

An important rule about math I learnt, that when it comes to division and multiplication, You have to do them from left to right (as they teach at schools), or You can easily mess up. No matter how attractive and tempting it looks. The order of operations matters.

Operation 1

-1 * abs(-123) // 10

can be simplified to:

-1 * 123 // 10

-123 // 10

floor(-123 / 10)

floor(-12.3)`

Floor goes 'downwards', so:

floor(-12.3)

-13

Operation 2.

abs(-123) // 10 * -1

can be simplified to:

`123 // 10 * -1

floor(123 / 10) * -1

Floor goes 'downwards' again, so:

floor(12.3) * -1

12 * -1

-12

Only addition and multiplication are commutative. Division and substraction aren't.