Why is exponentiation applied right to left?
The **
operator follows normal mathematical conventions; it is right-associative:
In the usual computer science jargon, exponentiation in mathematics is right-associative, which means that xyz should be read as x(yz), not (xy)z. In expositions of the BODMAS rules that are careful enough to address this question, the rule is to evaluate the top exponent first.
and from Wikipedia on the Order of Operations:
If exponentiation is indicated by stacked symbols, the usual rule is to work from the top down, because exponention is right-associative in mathematics.
So 2 ** 3 ** 4
is calculated as 2 ** (3 ** 4)
(== 2417851639229258349412352) not (2 ** 3) ** 4
(== 4096).
This is pretty universal across programming languages; it is called right-associativity, although there are exceptions, with Excel and MATLAB being the most notable.
Negative numbers with exponents in Python
Python parses print(-1**2)
in the following order:
Get's the exponent of
1 ** 2
Negates the result.
So it becomes this:
>>> -(1 ** 2)
-1
>>>
Because -1
translates to print(0 - 1 ** 2)
. But in the order of operations table, **
(exponents) is higher ranking than -
.
Therefore, Python math follows the order of operations in regular math, **
is more powerful (has more priority over) -
.
As mentioned on Wikipedia:
The acronym PEMDAS is common. It stands for Parentheses, Exponents, Multiplication/Division, Addition/Subtraction.
Also mentioned on the Python Docs:
Operator | Description |
---|---|
(expressions...), [expressions...], {key: value...}, {expressions...} | Binding or parenthesized expression, list display, dictionary display, set display |
x[index], x[index:index], x(arguments...), x.attribute | Subscription, slicing, call, attribute reference |
await x | Await expression |
** | Exponentiation |
+x, -x, ~x | Positive, negative, bitwise NOT |
*, @, /, //, % | Multiplication, matrix multiplication, division, floor division, remainder 6 |
Is Groovy Power Operator (**) Broken in Associativity?
No, it's not broken
It just has left to right associativity as with all other operators
In python **
has right to left associativity, so that's not broken either
They just have different rules
What are the ramifications of right-to-left and left-to-right associativity in C based languages?
For the most part, each operator has the associativity that makes the most sense for that operator.
All of the non-assignment binary operators have left-to-right associativity. This is useful for the obvious reason that English is read left-to-right and thus the evaluation of x + y + z
is consistent with how it is read. In addition, for arithmetic operators, the semantics match what we expect from the usage of the operators in mathematics.
Assignment operators have right-to-left associativity. Left-to-right assignment would have bizarre and unexpected semantics. For example, x = y = z
would result in x
having the original value of y
and y
having the original value of z
. It is expected that all three variables will have the same value after the expression is complete.
The prefix unary operators have right-to-left associativity, which makes sense because the operators closest to the operand are evaluated first, so in ~!x
, !x
is evaluated first, then ~
is applied to the result. It would be really, really weird were prefix operators applied with left-to-right associativity: to say that ~!x
means evaluate ~x
and then apply !
to the result is the complete opposite of how we think about expressions (or, at least, how most people think about expressions...).
Explanation of right to left binary method of modular arithmetic?
This algorithm is a combination of the Exponentiation by Squaring algorithm and modulo arithmetic.
To understand what's going on, first consider a situation when exponent
is a power of 2
. Then, assuming that exponent = 2 ^ k
, the result could be computed by squaring the result k
times, i.e.
res = (...((base ^ 2) ^2 ) ... ) ^2))
---------------------
k times
When exponent
is not a power of 2
, we need to make additional multiplications. It turns out that if we can divide exponent
by 2 without remainder, we can square the base, and divide the exponent. If, however, there is a remainder, we must additionally multiply the intermediate result by the value of the current base
.
What you see is the same exponentiation by squaring applied to modulo multiplication. The algorithm denotes integer division by two using the exponent >> 1
operation, which is identical to floor(exponent / 2)
.
Order of calculation
Your teacher is wrong. From https://docs.python.org/3/reference/expressions.html#evaluation-order:
6.15. Evaluation order
Python evaluates expressions from left to right. Notice that while
evaluating an assignment, the right-hand side is evaluated before the
left-hand side.
The *
has two expressions as its operands, 10**4
and 3**2
. The left operand, 10**4
is evaluated first, followed by the right operand, 3**2
.
Your teacher may be confused with a chain of exponentiations like 2 ** 3 ** 4
. Here the "outer" exponentiation has two arguments 2
and 3 ** 4
(rather than 2**3
and 4
, because of right associativity). However, the 2
is still evaluated before 3**4
.
For a simple expression like this, it doesn't really matter. But it could matter if one or both operands involved function calls with side effects. Consider something contrived like lambda: print(3) or 3)() + (lambda: print(4) or 4)()
. The value of the expression is 7 either way, but the order in which the print
functions are called will affect the output. Python, though, guarantees that 3
will be output before 4
.
Some languages (notably C, IIRC) don't specify an order of evaluation, so it is an implementation detail whether the left or right is evaluated first. This means you can't predict the value of something like i=3; j=(i++)*i
; j
could be either 3*3 == 9
or 4*3 == 12
, depending on whether i
is incremented before or after the right-hand operand is evaluated. (I don't recall if this is considered undefined behavior or implementation-defined behavior, though.)
Related Topics
How to Check If a Column Exists in Pandas
Working with Tiffs (Import, Export) in Python Using Numpy
Validating Detailed Types in Python Dataclasses
Parsing .Properties File in Python
How Can Pyspark Be Called in Debug Mode
Image Segmentation Based on Edge Pixel Map
Python Mixed Integer Linear Programming
Attributeerror: Module 'Cv2.Cv2' Has No Attribute 'Createlbphfacerecognizer'
What's the Cleanest Way to Extract Urls from a String Using Python
Shipping Python Modules in Pyspark to Other Nodes
Compile Main Python Program Using Cython
Django Query That Get Most Recent Objects from Different Categories
Constructing a Co-Occurrence Matrix in Python Pandas
Get the Position of the Largest Value in a Multi-Dimensional Numpy Array
Python Datetime to String Without Microsecond Component
Log Output of Multiprocessing.Process
Opencv Python Rotate Image by X Degrees Around Specific Point