[SOLVED]Function output anomaly (original) (raw)
I’ve been experimenting with some code from an old book, re-coding the C examples contained therein, into Python3 code and I’ve come across an operation of a custom function that I don’t understand.
Maybe someone could explain why I’m getting this anomaly, please.
The code (below) defines two function, that perform the same operation, in two different ways, the output from which is identical: raise x
to the power of n
where x
is first 2
and then -3
and n
is a integer value that increments from 0
to 9
The same operation is then performed using the Exponentiation Operator outside of a custom function, the output from which is correct.
The code:
#!/usr/bin/python3
def power(x,n): # raise x to the n-th power
p = 1
for i in range(n):
p *= x
return p
def expon(x,n):
p = (x**n)
return p
print('Output from the power() function')
for i in range(10):
print(f'2 ** {i} = {power(2,i):3.0f} | -3 ** {i} = {power(-3,i):6.0f}')
print('---------------------------------')
print('\nOutput from the expon() function')
for i in range(10):
print(f'2 ** {i} = {expon(2,i):3.0f} | -3 ** {i} = {expon(-3,i):6.0f}')
print('\nOutput from the Exponentiation Operator')
print('---------------------------------')
for i in range(10):
print(f'2 ** {i} = {2**i:3.0f} | -3 ** {i} = {-3**i:6.0f}')
The output:
Output from the power() function
2 ** 0 = 1 | -3 ** 0 = 1
2 ** 1 = 2 | -3 ** 1 = -3
2 ** 2 = 4 | -3 ** 2 = 9
2 ** 3 = 8 | -3 ** 3 = -27
2 ** 4 = 16 | -3 ** 4 = 81
2 ** 5 = 32 | -3 ** 5 = -243
2 ** 6 = 64 | -3 ** 6 = 729
2 ** 7 = 128 | -3 ** 7 = -2187
2 ** 8 = 256 | -3 ** 8 = 6561
2 ** 9 = 512 | -3 ** 9 = -19683
---------------------------------
Output from the expon() function
2 ** 0 = 1 | -3 ** 0 = 1
2 ** 1 = 2 | -3 ** 1 = -3
2 ** 2 = 4 | -3 ** 2 = 9
2 ** 3 = 8 | -3 ** 3 = -27
2 ** 4 = 16 | -3 ** 4 = 81
2 ** 5 = 32 | -3 ** 5 = -243
2 ** 6 = 64 | -3 ** 6 = 729
2 ** 7 = 128 | -3 ** 7 = -2187
2 ** 8 = 256 | -3 ** 8 = 6561
2 ** 9 = 512 | -3 ** 9 = -19683
Output from the Exponentiation Operator
---------------------------------
2 ** 0 = 1 | -3 ** 0 = -1
2 ** 1 = 2 | -3 ** 1 = -3
2 ** 2 = 4 | -3 ** 2 = -9
2 ** 3 = 8 | -3 ** 3 = -27
2 ** 4 = 16 | -3 ** 4 = -81
2 ** 5 = 32 | -3 ** 5 = -243
2 ** 6 = 64 | -3 ** 6 = -729
2 ** 7 = 128 | -3 ** 7 = -2187
2 ** 8 = 256 | -3 ** 8 = -6561
2 ** 9 = 512 | -3 ** 9 = -19683
Quercus (Quercus) July 23, 2022, 6:10pm 2
Hi Rob,
It appears to be an operator precedence issue, here, whereby the **
operator has higher precedence than the unary -
operator:
for i in range(10):
print(f'2 ** {i} = {2**i:3.0f} | -3 ** {i} = {-3**i:6.0f}')
To correct for that, we could use parentheses, as follows:
for i in range(10):
print(f'2 ** {i} = {2**i:3.0f} | -3 ** {i} = {(-3)**i:6.0f}')
EDIT:
This might be preferable to what is directly above, since it indicates explicitly in the output that parentheses are being used to control the order of operations:
for i in range(10):
print(f'2 ** {i} = {2**i:3.0f} | (-3) ** {i} = {(-3)**i:6.0f}')
rob42 (Rob) July 23, 2022, 6:50pm 3
Ah, right – I see where I’m misunderstanding this: I thought that it was the custom functions that were in error, producing alternating positive / negative results, thinking that all the -3
s should produce a negative output, which show my lack of understanding about the math.
Thank you.
rob42 (Rob) July 23, 2022, 7:11pm 4
Just one more question, if you don’t mind: how is it that this order of operation control is not required for the function called versions?
I would have expected that either all the outputs were correct or all the outputs were incorrect.
Quercus (Quercus) July 23, 2022, 7:25pm 5
Good question.
With both of your functions, the unary negation operation, when appropriate, is performed prior to any of the multiplication or exponentiation operations. For example, if you pass -3
as the first argument during a function call, that is what gets assigned to the x
parameter right at the outset, and therefore that negative value is what is used in any operations that follow that involve x
as an operand.
rob42 (Rob) July 23, 2022, 7:43pm 6
Again, my thanks to you – much appreciated.
steven.daprano (Steven D'Aprano) July 24, 2022, 12:52am 7
Your post is a massive overkill of a data dump! All you really needed to show is one example:
-3**2
# Expected 9 but got -9
If you really wanted to drive the point home, a second example would do:
# Use the builtin pow() function.
pow(-3, 2) # Returns 9 as expected.
The solution to this is simple: it is an operator precedence issue. Exponentiation has higher precedence than unary minus, as shown in the precedence table.
So the expression -3**2
is parsed as -(3**2)
but you are expecting (-3)**2
. That’s all it is.
steven.daprano (Steven D'Aprano) July 24, 2022, 12:59am 8
The operator precedence order applies when the interpreter parses an expression containing the operator, not to values which were created earlier using an operator.
So for example:
x = -3 # Unary operator.
x**2 # There is no unary operator here, so the result is (-3)*(-3)
-x**2 # Unary operator, so the result is -( (-3)*(-3) ) = -9
And you are correct about that! wink
The only thing is that you were computing two different expressions without realising that they were different. So naturally they returned different results. But both were correct, for the computation you were performing.
rob42 (Rob) July 24, 2022, 3:59am 9
Thanks for the reply.
The reason for my posting the way I did, was because I really did not understand what was going on with the alternating negative / positive output on the -3
side and it seemed (to me) to be better to post the output, rather than try to describe it (a picture being worth a 1000 words, and all that). Also I don’t see that 37 lines of output being too much of an issue; sorry if you disagree.
Yes, thank you. This has already been explained to me by @Quercus (did you not see that?).
Thank you for the link; very helpful.
rob42 (Rob) July 24, 2022, 4:07am 10
Yes, thank you.
But for my experimentation, I would not of realized my failure to understand the math, which I still don’t understand, to be honest, but that’s a different issue. I now know that all the -3
outputs should not be negative, contrary to my expectations.
Thanks again for your input.
{edit for typo}
Quercus (Quercus) July 24, 2022, 4:15am 11
If two negative numbers are multiplied, the result is positive. That is why all the even powers of -3 are positive.
All the odd powers of a negative number are odd.
rob42 (Rob) July 24, 2022, 4:53am 12
Thank you. I’ll brush-up on my math, so that I better understand what to expect when performing this kind of operation.
I do tend to focus on one topic at a time: Python when Programming, math when working with numbers. Clearly I need to do both at once, given this type of project, moving forward.
Thank you for your time and trouble; it’s been a big help to me.
{edit for typo: it’s kind of an OCD thing, with me}
mlgtechuser (Leland Parker) July 24, 2022, 4:31pm 13
No worries there, Mate. “OCD” is grossly overapplied and is improperly used where “caring about results” is actually the case. If someone can’t function until the pencils are all sharpened to the exact same length, that’s OCD.