Confused about operator precedence for 2^3x


#1

I’m getting reacquainted with Julia, and I’m confused about the order of operations as described here: https://docs.julialang.org/en/release-0.6/manual/integers-and-floating-point-numbers/

“The precedence of numeric literal coefficients is the same as that of unary operators such as negation. So 2^3x is parsed as 2^(3x), and 2x^3 is parsed as 2*(x^3).”

The docs for operator precedence (near the bottom here https://docs.julialang.org/en/latest/manual/mathematical-operations/) specify that ^ has a higher order of precedence than unary operators.

So why wouldn’t 2^3x be (2^3)x instead according to those rules?


#2

x = -5; y = 4
2^-x => 32
-2^x => domain error
-2^y => -16 (i.e parsed as -(2^y)), so the ^ does have precedence.
2x^y => 1250 (parsed as 2(x^y), which seems at least consistent to me)

These rules though can be confusing, so I prefer to always use parenthesis and never rely on precedence rules (having spent years supporting / implemententing a language [M/MUMPS => Caché ObjectScript] with only left to right precedence, i.e. 2+3*5 gives 30, not 17, and coding mostly in C/C++, switching back and forth between the two, I learned to practice safe ex(pressions), always wrap them in parens!)


#3

See the note in the manual:

The precedence of numeric literal coefficients used for implicit multiplication is higher than other binary operators

You can also use parse if you are unsure about precedence:

julia> parse("2^3x")
:(2 ^ (3x))

Personally, I try to avoid numeric literal coefficients, because I can never remember all the special cases and syntax conflicts (also in that section). But some people apparently find them useful.


#4

I’m the same way (and I don’t allow them in any code I review at work!)
I think the cons from all the special cases and syntax conflicts that numeric literal coefficients entail outweigh any pros for people who like expressions to look as much as possible like “math”, but of course, that’s just my opinion!


#5

I agree with both of you about liberal use of parentheses, that is my preference as well. When I was reading through the documentation I thought that literal coefficients was a a cool feature, but I was worried that there are too many rules to remember–especially since I am currently programming in a few different languages and there are already enough details to remember.

But with regards to understanding the rules, I’m still unsure if I am understanding the operator precedence correctly. If

which to me seems consistent with the fact that ^ has higher precedence than unary operators, then shouldn’t 2^(3x) parse as (2^3) * x? Does the 3x take precedence, even if the ^ has higher precedence because (2^-)*x (if you replaced the literal coefficient, 3, with a unary minus since the docs say they follow the same precedence) wouldn’t really make sense?


#6

But then wouldn’t 2x^3 be parsed as (2x)^3? It seems that it is parsed as 2 (x ^ 3).


#7

You’re correct that this doesn’t follow a normal precedence relation. Unwary operators, including juxtaposition, bind tighter than ^ on the right but looser on the left. This matches the convention of mathematical notation.


#8

Thanks for clearing that up. But is that something that should be made clear in the documentation? Or was I simply not looking in the right place?


#9

See the part I linked, it is documented:

The precedence of numeric literal coefficients is the same as that of unary operators such as negation. So 2^3x is parsed as 2^(3x), and 2x^3 is parsed as 2*(x^3).


#10

But that’s the part that confused me. Because then the next thing I did was to look up the operator precedence of unary operations and it said that ^ comes before unary operators, so 2^3x is parsed as 2^(3x) didn’t make sense to me the way they show as an example in the docs.

Maybe there is somewhere that describes unary operators in more detail than the operator precedence table. But just looking at that table I would have had no idea that

I guess a better question is where in the documentation is the information that @StefanKarpinski posted, and maybe there should be some link or tidbit in the operator precedence table?

Basically as a new Julia user who is learning Julia by reading through the docs, what should have been the process for me to understand how literal coefficients work without having to go onto the forums and ask for clarification?


#11

Your were looking in the right place in the manual. The link to the note pretty clear in how the literal up front is multiplied rather than raised to a power.


#12

This could definitely be clarified a bit if you wanted to make a PR to add this to the docs.


#13

I’ll consider doing a PR if I feel that I can sufficiently improve the documentation without spreading misinformation :sweat:


#14

Another good one is the expression: 6 / 2(1+2) as is described on YouTube here. As written this produces 1.0 but according to the PEMDAS rule for expression evaluation in mathematics the answer should be 9. Thoughts? Is this a bug in Julia or by-design?


#15

By design.