Order of operations Python - python

The order of operations in my code seems off...
numbers=[7, 6, 4]
result = 1
for num in numbers:
result *= num - 3
print(result)
In this code, I would expect the following to occur...
result=1
result = 1 * 7 - 3 = 7 - 3 = 4
result = 4 * 6 - 3 = 24 - 3 = 21
result = 21 * 4 - 3 = 84 - 3 = 81
HOWEVER, running the program outputs
result = 1
result = 1 * 7 - 3 = 1 * 4 = 4
result = 4 * 6 - 3 = 4 * 3 = 12
result = 12 * 4 - 3 = 12 * 1 = 12
Why with the *= operator is the order of operations altered?
My understanding is it does not have any special properties it merely saves space instead of writing:
result = result * num - 3
we get
result *= num - 3
and for some reason.. (result = result * num - 3) != (result *= num - 3)

Why with the *= operator is the order of operations altered?
The *= is not an operator, it's delimiter. Check the '2. Lexical analysis' of 'The Python Language Reference':
The following tokens are operators:
+ - * ** / // % #
<< >> & | ^ ~ :=
< > <= >= == !=
The following tokens serve as delimiters in the grammar:
( ) [ ] { }
, : . ; # = ->
+= -= *= /= //= %= #=
&= |= ^= >>= <<= **=
The period can also occur in floating-point and imaginary literals. A
sequence of three periods has a special meaning as an ellipsis
literal. The second half of the list, the augmented assignment
operators, serve lexically as delimiters, but also perform an
operation.
Moreover, in your code you have the, augmented assignment statement, as per '7.2.1. Augmented assignment statements':
Augmented assignment is the combination, in a single statement, of a binary operation and an assignment statement:
[...]
An augmented assignment evaluates the target (which, unlike normal
assignment statements, cannot be an unpacking) and the expression
list, performs the binary operation specific to the type of assignment
on the two operands, and assigns the result to the original target.
The target is only evaluated once.
An augmented assignment expression like x += 1 can be rewritten as x =
x + 1 to achieve a similar, but not exactly equal effect. In the
augmented version, x is only evaluated once. Also, when possible, the
actual operation is performed in-place, meaning that rather than
creating a new object and assigning that to the target, the old object
is modified instead.
Unlike normal assignments, augmented assignments evaluate the
left-hand side before evaluating the right-hand side. For example,
a[i] += f(x) first looks-up a[i], then it evaluates f(x) and performs
the addition, and lastly, it writes the result back to a[i].
The '6.16. Evaluation order' says:
Python evaluates expressions from left to right. Notice that while evaluating an assignment, the right-hand side is evaluated before the left-hand side.
You can also check the '6.17. Operator precedence' chapter, but it's not about the statements.

The expression on the right hand side of the *= is evaluated first.
7 - 3 => 4 which multiplied by 1 is 4.
6 - 3 => 3 which multiplied by 4 is 12.
4 - 3 => 1 which multiplied by 12 is 12.
To achieve what you are expecting:
numbers = [7, 6, 4]
result = 1
for num in numbers:
result = result * num - 3
print(result)

numbers=[7, 6, 4]
result = 1
for num in numbers:
result *= num-3
print(result)
The *= operator is a compound assignment operator, which means that it combines the assignment operator = with another operator
https://www.educative.io/answers/what-are-the-compound-assignment-identity-operators-in-python
numbers=[7, 6, 4]
result = 1
for num in numbers:
result = result*num-3
print(result)

the *= means that the * will be used between what's before it and what's after so you need to get result_2 in this example to get what you want :
numbers = [7,6,4]
result = 1
result_2 = 1
for number in numbers:
result *= number -3
result_2 = result_2 * number -3
print(result, result_2)

Related

Dividing two numbers and printing the result and adding one to the result if there is a remainder, without using if-statements or imports or function? [duplicate]

This question already has answers here:
Is there a ceiling equivalent of // operator in Python?
(9 answers)
Closed 10 days ago.
I'm trying to divide number into groups in plain python without importing or the use of if-statements, and get the division into groups + remainder forming one extra group so that 200 / 99 would be 3, And 7 / 3 would be 3, but that 8 / 4 would still be just 2, and 4 / 2 would be 2 etc.. I cannot import anything so it needs to be in plain python.
I tried storing the numbers from inputs from user into variables and dividing them, and then adding one. I also tried // and adding 1 but I cannot get it to work.
How about this:
a, b = 200, 99
result, remainder = a // b + int(bool(a % b)), a % b
This computes the result by performing an integer divide a // b and computing the remainder a % b. Converting an integer value to a boolean is False for 0 and True for any other value, and converting that back to an integer gives you the value you want to add to the result. The remainder is computed again to assign it, if you need it.
As user #markransom commented, the conversion to int() isn't even necessary, as bool already 'is' an integer type:
>>> isinstance(True, int)
True
So, this works (although it may be considered a bit less readable):
a, b = 200, 99
result, remainder = a // b + bool(a % b), a % b
If you're using a modern version of Python and really want it to be short, this also works:
result = a // b + bool(remainder := a % b)
This uses the walrus operator to assign the remainder when it is first computed, avoiding having to compute it twice as well.
Python boolean operations short-circuit and return the last value evaluated and you can use that to convert a non-zero remainder to 1 for addition to a quotient
def group_me(dividend, divisor):
quotient, remainder = divmod(dividend, divisor)
return quotient + (remainder and 1 or 0)
print(group_me(200, 99))
print(group_me(7, 3))
print(group_me(8, 4))
Output
3
3
2
If remainder is non-zero, remainder and 1 short-circuits and returns 1. Otherwise, the or now becomes 0 or 0, which retains its last value 0.
You could do an if statement mathematically without using if itself:
n, d = 200, 99
x, y = n/d, n//d + 1
result = int((x%1 == 0) * x + (x%1 != 0) * y)
Essentially it is condition * answer 1 + (1 - condition) * answer 2. Then it switch to whichever answer depending on condition being 1 or 0.

Regarding left-sided Binding in Python

I'm new to Python and I'm still learning. I've learned the concept of left-sided binding when using operators (and it was taught that only exponentiation uses RIGHT-SIDED BINDING). It was also taught to me that, both * and / have equal priority and Binding of the operator determines the order of computation performed by some operators with equal priority, put side by side in one expression.
But now when teaching compound assignment operators, they used the following example
a = 6
b = 3
a /= 2 * b
print(a)
The answer given is 1.0.
The explanation they have given is as follows.
2 * b = 6
a = 6 → 6 / 6 = 1.0
My question is, isn't a/=2*b is the same thing as a=a/2*b. So when considering a=a/2*b shouldn't the division be considered first becuase of the left sided binding and then the multiplication later.
a = 6 → 6/2 = 3.0
3.0 * b = 9.0.
So shouldn't 9.0 be the answer. Please explain this to me.
The statement a /= 2 * b is equivalent to a /= (2 * b), not (a /= 2) * b, which doesn't make sense in Python.
If you did interpret it as (a /= 2) * b, then it would expand to (a = a / 2) * b, not a = (a / 2) * b. This is not allowed in Python because a = a / 2 is not an expression and it does not produce a value which could be multiplied by b.
The answer is that the assignment operator _ = _, and the augmented assignment operators like _ /= _, have a lower precedence than other operators (like _ * _ and _ / _), and they are "right-associative" syntactically so that a = b = c assigns the result c to both a and b; however, it would not be correct to write that this is equivalent to a = (b = c), since this does not make sense in Python for the above reason. Still, _ ** _ is not the only right-associative operator in Python: another one is the ternary operator _ if _ else _, where an expression a if b else c if d else e is equivalent to a if b else (c if d else e), not (a if b else c) if d else e.
Python follows the usual order of operations used in math, where exponents take priority over multiplication/division and they, in turn, over addition/subtraction. Compound operators are the last in this order. So in your example, 2*b is evaluated first and returns 6. Then a/=6 is evaluated and returns 1.

Basic operation giving different results in Python

I was playing around with few basic operations in Python 3 and came across this
Code 1:
a = 6
b = 3
a = a / 2 * b
print(a)
Output is 9.0
In one of the trainings I have seen that
a = a / 2
can be written as
a /= 2
So I re-wrote my above code as below
Code 2:
a = 6
b = 3
a /= 2 * b
print(a)
But now the output is 1.0.
I was expecting 9.0 as output. Can someone help me understand why code behaves this way?
In the case of a /= 2 * b, you saying that a will be divided by expression after /=.
In other words, your expression could be rewritten as a = a / (2 * b) where a = 6, b = 3
in
a /= 2 * b
the 2 * b is carried out first so if b == 3 it can be rewritten as:
a /= 6
That's because they perform operations in different order.
The first of block of code divides a (6) by 2 and then multiplies that result by b (3)
E.g. (6 / 2) * 3 = 9
However the second block of code does the following:
6 / (2 * 3) = 1
Note, that
a /= 2 * b
is basically
a = a / (2 * b)
The previous code is different. It's not like the above (look at the parentheses)
a = a / 2 * b
This is different than
a = a / (2 * b)
Because the first code interpret it as division and then multiply, while the second code interpret it as multiply (bottom) and then division.
as you can see in the documentatiopn on operator precedence * and / have the same precedence. two operations with the same precedence are executed from left to right:
Operators in the same box group left to right
so your first example is evaluated as
(a / 2) * b
the second as
a / (2 * b)
regarding your comment
a = a / 2 and a /= 2 are always equivalent, right?
for the built-in python numbers you are right.
for your own classes you can make the operations differ. if a is an insance of a custom class a/x will call __truediv__(self, other) while a/=x will call __itruediv__(self, other) as described in the data model.
I'm surprised none of the other answers mention this, but the reason doesn't have anything to do with math, order of operations or implicit parentheses.
x /= y is just another way of saying x.__itruediv__(y). Your second example is not equivalent to your first example, because parameters are evaluated before being passed in to a function call. So, a /= 2 * b is equivalent to a.__itruediv__(2 * b), and naturally, the expression 2 * b must be evaluated before being passed in to __itruediv__.

Exercise on Summing Digits | What's with n // = 10 [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
What is the reason for having ‘//’ in Python?
While trying to do an exercise on summing digits, I stumbled on this solution:
def sum_digits(n):
import math
total = 0
for i in range(int(math.log10(n)) + 1):
total += n % 10
n //= 10
return total
My question is, what does the second to last line do? How is that proper syntax?
That implements what is called floor division. Floor division (indicated by // here) truncates the decimal and returns the integer result, while 'normal' division returns the answer you may 'expect' (with decimals). In Python 3.x, a greater distinction was made between the two, meaning that the two operators return different results. Here is an example using Python 3:
>>> 10 / 3
3.3333333333333335
>>> 10 // 3
3
Prior to Python 3.x, there is no difference between the two, unless you use the special built-in from __future__ import division, which then makes the division operators perform as they would in Python 3.x (this is using Python 2.6.5):
In [1]: 10 / 3
Out[1]: 3
In [2]: 10 // 3
Out[2]: 3
In [3]: from __future__ import division
In [4]: 10 / 3
Out[4]: 3.3333333333333335
In [5]: 10 // 3
Out[5]: 3
Therefore when you see something like n //= 10, it is using the same +=/-=/*=/etc syntax that you may have seen, where it takes the current value of n and performs the operation before the equal sign with the following variable as the second argument, returning the result into n. For example:
In [6]: n = 50
In [7]: n += 10
In [8]: n
Out[8]: 60
In [9]: n -= 20
In [10]: n
Out[10]: 40
In [11]: n //= 10
In [12]: n
Out[12]: 4
// is the floor division operator. It always truncates the return value to the largest integer smaller than or equal to the answer.
The second to last line is a combination of operators, in a way, including an uncommon one, which is why it's a little confusing.
Let's piece it apart.
First, // in Python is floor division, which basically is division rounded down to the nearest whole number. Thus,
>>> 16//5
3
>>> 2//1
2
>>> 4//3
1
>>> 2//5
0
Finally, the = is there because of a Python syntax that allows one to perform an operation on a variable, and then immediately reassign the result to the variable. You've probably seen it most commonly in +=, as:
>>> a = 5
>>> a += 7
>>> a
12
In this case, //= means "perform floor division, floor dividing the variable by the second argument, then assign the result to the original input variable." Thus:
>>> a = 10
>>> a //= 6
>>> a
1
for the assignment in Python A += B equals to A = A + B ,A *= B equals to A = A * B
same thing applies to "Floor Divide" as well , A //= B equals to A = A // B
Floor Division means return the truncated integer number
>>> 5 // 3 # 1.6
1 # 0.6 will be throw off

modulus of negative numbers in Python [duplicate]

This question already has answers here:
How does the modulo (%) operator work on negative numbers in Python?
(12 answers)
Closed last month.
23 % -5 = -2
23 % 5 = 3
Can someone explain to me how I can understand this because I have an exam tomorrow. I want to say its because -5 * -5 =25 then 25 -2 = 23 which is how they get the 23. Is this correct?
In Python, the sign of the remainder is the same as the sign of the denominator (which differs from languages like C, where it is the same as the sign of the numerator).
Mathematically, you are always guaranteed that if a, b = divmod(n, d), then a*d + b == n.
Note that 23//5 == 4 and 23//-5 == -5 (Python always does floor division). Thus, we have 4*5 + 3 == 23 and -5*-5 - 2 == 23, as you have said.
Lets write it out as N=kM+R.
We have 23 = -5*(-5) - 2, and 23 = 4*5 + 3.
The simplest way of looking at problem for your purposes is to consider the definition that:
a mod n = R where the remainder R must satisfy 0<= R
So for mod -5 arithmetic, 0<= R < -4 i.e. R can be one of 0, -1, -2, -3, -4
that is you effectively subtract (or add) n from a until you bring R into the range above:
So
23 % 5 is (23-4*5) = 23-20 = 3
but
23 % -5 is (23+5*(-5)) = 23-25 = -2
Well, 23 % 5 = 3 since 4*5 = 20 and when you divide 23 by 20 you obtain a remainder of 3. You can think of it as the closet you can go without going over.
As for 23 % -5, well that answer differs from one programming language to another.
For Python it's -2 because it will always return the value of the divisor and it's because 5*5 = 25 and when you divide 23 by 25 in Python you obtain a remainder of -2 (since it must be negative because the divisor was negative) so we have 25 - 2 = 23.
It's worth noting that the formal mathematical definition states that b is a positive integer.
% in Python uses "Modulo operation" ; it's different from taking the reminder of a division operation such that.
a - int(a/n) * n
although it is sometimes equivalent in some computer languages.
The math expression can be found explict here: http://en.wikipedia.org/wiki/Modulo_operation
So obviously, in Python "%" operation uses the following expression:
mod(a, n) = a - n * floor(a / n)
Therefore,
23%-5 = mod(23,-5) = 23 - (-5) * floor(23/-5) = 23 - (-5) * -5 = -2
and
23%5 = mod(23, 5) = 23 - 5 * floor(23/5) = 23 - 5 * 4 = 3
In addition, you my find it's interesting that
-23%5 = mod(-23,5) = (-23) - 5 * floor(-23/5) = -23 - 5 * (-5) = 2
since floor() action will take the integer value toward negative infinity.

Categories

Resources