[SOLVED]Function output anomaly

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

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}')
2 Likes

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 -3s should produce a negative output, which show my lack of understanding about the math.

Thank you.

2 Likes

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.

1 Like

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.

Again, my thanks to you – much appreciated.

1 Like

Your post is a massive overkill of a data dump! :slight_smile: 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.

1 Like

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.

1 Like

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.

1 Like

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}

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.

1 Like

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}

1 Like

No worries there, Mate. “OCD” is grossly overapplied and is improperly used where “caring about results” is actually the case. :blush: If someone can’t function until the pencils are all sharpened to the exact same length, that’s OCD.