0

Recently I encountered a problem:

I want to calculate various roots of various numbers like this:

x = x ** 1/y+1

None of the methods I know result in a working code.

Method 1:

x = 54
y = 2
x = x ** 1/y+1
print(x)

Printed value is 28.0 instead of 3.7798

Method 2:

x = 54
y = 2
x = x ** 1/(y+1)
print(x)

Printed value is 18.0 istead of 3.7798

Method 3:

x = 216
y = 2
x = x ** (1/(y+1))
print(x)

Printed value is 5.99 instead of 6

Is there a way that would work with y being up to 20?

Edit:

Another suggested method:

def nth_root(val, n):
    ret = int(val**(1./n))
    return ret + 1 if (ret + 1) ** n == val else ret

y = 1
print(nth_root(19, (y+1)))

prints 4

  • 1
    for starters, https://docs.python.org/3/reference/expressions.html#operator-precedence – njzk2 Jan 27 '16 at 00:22
  • You should look up "operator precedence" for Python, which would indicate that you need the parentheses as shown in your 3rd attempt. As far as the 5.99 answer is concerned, I did not get that when I tried your example. I suspect there's more context to your scenario than you've described. – lurker Jan 27 '16 at 00:23
  • also, third example gives 6.0. – njzk2 Jan 27 '16 at 00:24
  • @njzk2 I get `5.999999999999999` in 3.4. – grc Jan 27 '16 at 00:26
  • `5.999999999999999` in 3.5 too. I thought 3.x had the intelligent repr thing? – nneonneo Jan 27 '16 at 00:27

5 Answers5

3

You don't seem to understand (yet) order of operations in a programming language. You need parentheses to make sure you add 1 to y, then take the reciprocal, and then use that as an exponent. The "natural" order is the opposite.

x = x ** (1.0/(y+1))
Prune
  • 76,765
  • 14
  • 60
  • 81
  • 3
    Well, no ... it must have been Python 3, in which division is floating point by default. Or the result would have been different. – Tom Zych Jan 27 '16 at 00:24
  • x = 216 y = 2 x = x ** (1.0/(y+1)) print(x) still prints 5.9999 – Mantas Kandratavičius Jan 27 '16 at 00:25
  • @Tom Zych: thanks; I've updated the answer. – Prune Jan 27 '16 at 00:27
  • There has to be something I'm missing... My last method looks exactly like yours just with .0 added. Even if I add the .0, I still get 5.99 printed. So is it that ,,I don't seem to understand'' or your way doesn't solve my problem either? – Mantas Kandratavičius Jan 27 '16 at 00:32
  • 1
    @MantasKandratavicius use [this method](http://stackoverflow.com/a/15978862/645956). – grc Jan 27 '16 at 00:32
  • @grc Thanks for a new method but it either doesn't work or im doing something wrong again. def nth_root(val, n): ret = int(val**(1./n)) return ret + 1 if (ret + 1) ** n == val else ret y = 1 print(nth_root(19, (y+1))) prints 4 – Mantas Kandratavičius Jan 27 '16 at 00:49
  • If you want to guarantee exact arithmetic in integer cases, you need to use an integer-preserving algorithm. Binary computers do not perform exact arithmetic: they round to the nearest binary representation, given their precision levels. Trying printing the value of 1.0/3, and you'll see that it's not an infinite series of 3's; this is why the resulting operation comes up a little off your expectation. – Prune Jan 27 '16 at 00:51
3

Since everyone else has already told you why your Method 3 is correct, I'll stick to getting you an accurate answer. You can read more about why you're not getting exactly 6, but basically it's because your computer doesn't represent the 1/3 exactly when doing the calculation and makes the final answer off.

So, the easiest solution is to use sympy:

import sympy

y = 216
x = 2
x = sympy.root(y,x+1)
print(x)
Carson
  • 139
  • 1
  • 5
2

What you want is this (assuming you are using Python 3):

x = x ** (1/(y+1))

For Python 2, either of the following will work:

from __future__ import division
x = x ** (1/(y+1))

or (also fine on Python 3):

x = x ** (1.0/(y+1))

The issue is you need to apply the parentheses in the correct locations to get the order of operations right.

Method 3 is to do with floating point arithmetic. See: https://docs.python.org/3.5/tutorial/floatingpoint.html

For more info on Python 2 vs. Python 3 division: Division in Python 2.7. and 3.3

Community
  • 1
  • 1
vk1011
  • 7,011
  • 6
  • 26
  • 42
0

Only your last code works because ** has higher precedence than / (and / has higher precendence than +).

The value is not exactly 6, because floating point numbers are not perfectly accurate. A third can not be represented as a float.

Joonazan
  • 1,408
  • 10
  • 18
0

All your values are just as expected. According to the python operator precedence:

x ** 1/y+1 is parsed as ((x ** 1) / y) + 1, and

x ** 1/(y+1) is actually (x ** 1) / (y + 1).

What you probably want is x ** (1. / (y + 1)). Note, that 1. is a floating point number, causing the whole expression to be evaluated as floats. This also means that you will work with finite precision, e.g., getting 5.99999 instead fo 6 is to be expected.

Elmar Peise
  • 14,014
  • 3
  • 21
  • 40