Infinite exponent loop - Python - python

I'm trying to create a function that takes a value x, and creates a pattern like this with n+1 square root terms: sqrt(x)^sqrt(x)^sqrt(x)^sqrt(x)^sqrt(x)...
def func(x,n):
a = x**0.5
i = 0
while i < n:
a = a ** (x**0.5)
i += 1
print a
For example using x = 2, the function does not converge (to 2), but increases exponentially in some way, I don't understand why.
For the first iteration (i=0) it seems to be correct, as it calculates, sqrt(2)^sqrt(2), but for the second iteration (i=1) it gives me 2.0, and it keeps increasing.
Thanks!

The above answer by #interjay illustrates what the problem is with the iterative method. As an alternative, you could also use a recursive method to calculate this
from math import sqrt
def fun(x,n):
if n == 0:
return sqrt(x)
else:
return sqrt(x) ** fun(x, n-1)
>>> fun(2,2)
1.7608395558800285
>>> fun(2,3)
1.8409108692910108
>>> fun(2,10)
1.988711773413954
>>> fun(2,100)
2.0000000000000004

For sqrt(x)^sqrt(x)^sqrt(x)... to converge, the exponentiation needs to be treated as right-associative, i.e. sqrt(x)^(sqrt(x)^(sqrt(x)^...)). But your code is calculating it as left-associative: ((...^sqrt(x))^sqrt(x))^sqrt(x).
You need to switch the order of terms in
a = a ** (x**0.5)
to
a = (x**0.5) ** a

Related

How to turn this code into a one-liner or make it shorter?

I am a middle school student and just started learning about functions. This code is about exponents, but I cannot use import math. Is there a way to make this code into a one-liner or make it shorter?
def power(a, n):
x = 1
if n == 0:
print(1)
elif n > 0:
for i in range(n):
x = x * a
else:
for i in range(-n):
x = x * a
return x
print(power(2, 5))
You can use the pow function instead of "x = x * a". Also even if you don't want to use that function, you can simplify it as "x *= a".
You could look into recursive functions, they are a bit tricky at first but are a good brain exercise.
A recursive power function would look like that :
def power(a, n):
if n == 0:
return 1
elif n == 1:
return a
else:
return a * power(a, n-1)
You can use the in-built operator **.
Example:
print(2**2) # Will return 4
Use the ** operator directly:
print(2 ** 5)
You can use this
**
which will return the value of 4 to the power of 3 (same as 4 * 4 * 4):
You can use ** This is an exponentiation operator.
def power(a, n):
return a**n
print(power(2, 5))
or simply use lambda function. You can read about it here.
print((lambda x,y:x**y)(2,5))
If you want to shorten your function with one line, you can use lambda statements like this: Shortening code with lambda statement in python
And you can use the ** builtin operator in place of multiplying the number over and over in a loop. So for example, 5**4 is equivalent to 5 * 5 * 5 * 5 and will give the exact same output.
P.S. I am also just beginning with programming, so I might not have the best answer.
If the goal is to use your own function. You can shorter an if with:
value_when_true if condition else value_when_false;
Putting a simple if-then-else statement on one line
I can see your overall need is to get the power of x.
If you can't use import math, then go with the inbuilt arithmetic operator for exponential that is **
Ex. You need 5 to the power 4 then code will be
print(5**4) # In one line
def power(b,n):
n=abs(n)
print(b**n)
print(power(2,-5))
well how about this here you can use the abs function to convert negative number to positive so no need for extra code simple use of ** can do everything

Writing a Factorial function in one line in Python

I am looking to improve my coding by performing the same code in different ways, this not only is to help me become better at coding but also understand different people's code and their coding style. Can someone explain how I might be able to right a factorial function similar to the one posted below in one line? Also using lambda functions are welcome too.
def factorial(number):
fact = 1
for i in range(1, number + 1):
fact *= i
return fact
I know I can write this recursively but I have chosen not to do it that way.
Here is my one-liner solution without importing anything.
def factorial(n: int):
return n * factorial(n - 1) if n > 1 else 1
It recurses until the input number is 1, where it finally returns the result (in the case of n=0, it returns 1 since 0!=1). The solution also uses the ternary operator fit an if...else into one line.
Note that python has a maximum recursion, so factorial(x) where x >= 999 will result in a RecursionError
You can use reduce to write a factorial function.
from operator import mul
# from functools import reduce # Python3 only
def factorial(x):
return reduce(mul, range(1, x + 1), 1)
factorial(5) # 24
You can also import it from the math module which additionally raises exceptions for negative and non-integral numbers.
from math import factorial
Similar to YulkyTulky's answer, it is also possible to write the one liner just using Boolean logic and without an if.
factorial = lambda x : x and x * factorial(x - 1) or 1
The x and x * factorial(x - 1) part returns a value as long as x is not zero, but when x is zero, the function returns 1, ending the recursion.
factorial(4) # 24
This would be my answer
factorial = lambda num: 1 if num <= 1 else num * factorial(num-1)
You can write a one-line lambda function with the help of the built-in function reduce (although you will have to import reduce from functools if you upgrade to Python 3.x). Note that the last argument sets the initial value to 1 so that 0! can still work:
lambda x: reduce(int.__mul__, range(1, x + 1), 1)
so that:
print((lambda x: reduce(int.__mul__, range(1, x + 1), 1))(4))
would output 24, for example.
So the simplest option (i think) would be to create a string that you can then evaluate using the built in eval method, so we are essentially eval('1 * 2 * 3...')
factorial = lambda num: eval('*'.join([str(each) for each in range(1, num + 1)]))
print(factorial(3))
if you would want a more formatted solution you could simply create a formatted-string with your desired format, what i mean is:
factorial_formatted = lambda num: '{}! = {}'.format(
num, eval('*'.join([str(each) for each in range(1, num + 1)])))
print(factorial_formatted(3))
output respectively would be: 6, 3! = 6
Factorials in Python
factorial = math.gamma(n + 1)
Example Program
import math
def get_factorial(n):
try:
print(math.gamma(n + 1))
except ValueError:
print("Domain Error: −n /∈ ℤ")
except OverflowError:
print("Overflow Error")
except Exception as e:
print(f"{e}")
n = float(input("Enter n for n! : "))
get_factorial(n)
Note: works for real numbers e.g. -2.90! = 5.56
Another way:
factorial = lambda x: x if x==1 else x * factorial(x-1)

How can I make this python function run O(log n) time instead of O(n) time?

def findMax(f,c):
n=1
while f(n) <= c:
n += 1
return n
This is a higher-order python function that given function f and a maximal count,
c returns the largest n such that f(n) ≤ c. This works but not when n gets too large for e.g f(10**6). How can I make this algorithm run O(log n) time so it can facilitate f(10**6) using the function below?
def f(n):
return math.log(n, 2)
Change n += 1 to n *= 2 for logarithmic outcome.
Logarithmic sequences increment in multiples of 2, and are non-linear, thus logarithmic sequences don't increment by 1.
Use a search algorithm to find the solution faster. This is an implementation using jpe.math.framework.algorythems.brent which is an implementation of the brent search algorithm.
import math
import jpe
import jpe.math.framework.algorythems
def f(x):
return math.log(x, 2)
value = 9E2
startVal = 1E300
val = int(jpe.math.framework.algorythems.brent(f, a=0, b=startVal, val=value, mode=jpe.math.framework.algorythems.modes.equalVal)[0])#takes 37 iters
print(val)
Alternatively in this scenario with this f:
the result is within 1 of 2**c (c as passedto findMax)

Different implementations of Newton's method in floating point arithmetic

I'm solving a one dimensional non-linear equation with Newton's method. I'm trying to figure out why one of the implementations of Newton's method is converging exactly within floating point precision, wheres another is not.
The following algorithm does not converge:
whereas the following does converge:
You may assume that the functions f and f' are smooth and well behaved. The best explanation I was able to come up with is that this is somehow related to what's called iterative improvement (Golub and Van Loan, 1989). Any further insight would be greatly appreciated!
Here is a simple python example illustrating the issue
# Python
def f(x):
return x*x-2.
def fp(x):
return 2.*x
xprev = 0.
# converges
x = 1. # guess
while x != xprev:
xprev = x
x = (x*fp(x)-f(x))/fp(x)
print(x)
# does not converge
x = 1. # guess
while x != xprev:
xprev = x
dx = -f(x)/fp(x)
x = x + dx
print(x)
Note: I'm aware of how floating point numbers work (please don't post your favourite link to a website telling me to never compare two floating point numbers). Also, I'm not looking for a solution to a problem but for an explanation as to why one of the algorithms converges but not the other.
Update:
As #uhoh pointed out, there are many cases where the second method does not converge. However, I still don't know why the second method converges so much more easily in my real world scenario than the first. All the test cases have very simple functions f whereas the real world f has several hundred lines of code (which is why I don't want to post it). So maybe the complexity of f is important. If you have any additional insight into this, let me know!
None of the methods is perfect:
One situation in which both methods will tend to fail is if the root is about exactly midway between two consecutive floating-point numbers f1 and f2. Then both methods, having arrived to f1, will try to compute that intermediate value and have a good chance of turning up f2, and vice versa.
/f(x)
/
/
/
/
f1 /
--+----------------------+------> x
/ f2
/
/
/
"I'm aware of how floating point numbers work...". Perhaps the workings of floating-point arithmetic are more complicated than imagined.
This is a classic example of cycling of iterates using Newton's method. The comparison of a difference to an epsilon is "mathematical thinking" and can burn you when using floating-point. In your example, you visit several floating-point values for x, and then you are trapped in a cycle between two numbers. The "floating-point thinking" is better formulated as the following (sorry, my preferred language is C++)
std::set<double> visited;
xprev = 0.0;
x = 1.0;
while (x != prev)
{
xprev = x;
dx = -F(x)/DF(x);
x = x + dx;
if (visited.find(x) != visited.end())
{
break; // found a cycle
}
visited.insert(x);
}
I'm trying to figure out why one of the implementations of Newton's method is converging exactly within floating point precision, wheres another is not.
Technically, it doesn't converge to the correct value. Try printing more digits, or using float.hex.
The first one gives
>>> print "%.16f" % x
1.4142135623730949
>>> float.hex(x)
'0x1.6a09e667f3bccp+0'
whereas the correctly rounded value is the next floating point value:
>>> print "%.16f" % math.sqrt(2)
1.4142135623730951
>>> float.hex(math.sqrt(2))
'0x1.6a09e667f3bcdp+0'
The second algorithm is actually alternating between the two values, so doesn't converge.
The problem is due to catastrophic cancellation in f(x): as x*x will be very close to 2, when you subtract 2, the result will be dominated by the rounding error incurred in computing x*x.
I think trying to force an exact equal (instead of err < small) is always going to fail frequently. In your example, for 100,000 random numbers between 1 and 10 (instead of your 2.0) the first method fails about 1/3 of the time, the second method about 1/6 of the time. I'll bet there's a way to predict that!
This takes ~30 seconds to run, and the results are cute!:
def f(x, a):
return x*x - a
def fp(x):
return 2.*x
def A(a):
xprev = 0.
x = 1.
n = 0
while x != xprev:
xprev = x
x = (x * fp(x) - f(x,a)) / fp(x)
n += 1
if n >100:
return n, x
return n, x
def B(a):
xprev = 0.
x = 1.
n = 0
while x != xprev:
xprev = x
dx = - f(x,a) / fp(x)
x = x + dx
n += 1
if n >100:
return n, x
return n, x
import numpy as np
import matplotlib.pyplot as plt
n = 100000
aa = 1. + 9. * np.random.random(n)
data_A = np.zeros((2, n))
data_B = np.zeros((2, n))
for i, a in enumerate(aa):
data_A[:,i] = A(a)
data_B[:,i] = B(a)
bins = np.linspace(0, 110, 12)
hist_A = np.histogram(data_A, bins=bins)
hist_B = np.histogram(data_B, bins=bins)
print "A: n<10: ", hist_A[0][0], " n>=100: ", hist_A[0][-1]
print "B: n<10: ", hist_B[0][0], " n>=100: ", hist_B[0][-1]
plt.figure()
plt.subplot(1,2,1)
plt.scatter(aa, data_A[0])
plt.subplot(1,2,2)
plt.scatter(aa, data_B[0])
plt.show()

How do you a double factorial in python?

I've been stucked on this question for a really long time.
I've managed to do a single recursive factorial.
def factorial(n):
if n == 0:
return 1
else:
return n * factorial(n-1)
Double factorial
For an even integer n, the double factorial is the product of all even positive integers less than or equal to n. For an odd integer p, the double factorial is the product of all odd positive integers less than or equal to p.
If n is even, then n!! = n*(n - 2)*(n - 4)*(n - 6)* ... *4*2
If p is odd, then p!! = p*(p - 2)*(p - 4)*(p - 6)* ... *3*1
But I have no idea to do a double factorial. Any help?
from functools import reduce # only in Python 3
reduce(int.__mul__, range(n, 0, -2))
Isn't that just the same as the factorial with a different ending condition and a different parameter to the recursion call?
def doublefactorial(n):
if n <= 0:
return 1
else:
return n * doublefactorial(n-2)
If n is even, then it will halt when n == 0. If n is odd, then it will halt when n == -1.
The problem here is that the double factorial is defined for negative real numbers (-1)!! = 1, (-3)!! = -1 (even negative integers (such -2, -4, ...) should have solution as +/- inf) so... something is smelling bad in all solutions for negative numbers. If one want to define the double factorial for al reals those solutions don't work. The solution is to define the double factorial using gamma function.
import scipy.special as sp
from numpy import pi
def dfact(x):
n = (x + 1.)/2.
return 2.**n * sp.gamma(n + 0.5)/(pi**(0.5))
It works! :D
Starting Python 3.8, we can use the prod function from the math module which calculates the product of all elements in an iterable, which in our case is range(n, 0, -2):
import math
math.prod(range(n, 0, -2))
Note that this also handles the case n = 0 in which case the result is 1.
My version of the recursive solution, in one line:
dfact = lambda n: (n <= 0) or n * dfact(n-2)
However, it is also interesting to note that the double factorial can be expressed in terms of the "normal" factorial. For odd numbers,
n!! = (2*k)! / (2**k * k!)
where k = (n+1)/2. For even arguments n=2k, although this is not consistent with a generalization to complex arguments, the expression is simpler,
n!! = (2k)!! = 2*k * k!.
All this means that you can write code using the factorial function from the standard math library, which is always nice:
import math
fact = math.factorial
def dfact(n):
if n % 2 == 1:
k = (n+1)/2
return fact(2*k) / (2**k * fact(k))
else:
return 2**k * fact(k)
Now, this code is obviously not very efficient for large n, but it is quite instructive. More importantly, since we are dealing with standard factorials now, it is a very good starting point for optimizations when dealing with really large numbers. You try to use logarithms or gamma functions to get approximate double factorials for large numbers.
def doublefactorial(n):
if n in (0, 1):
return 1
else:
return n * doublefactorial(n-2)
should do it.
def double_fact(number):
if number==0 or number==1:
return 1
else:
return number*double_fact(number-2)
I think this should work for you.
I hope I understand it correctly, but will this work
def factorial(n):
if n == 0 or n == 1:
return 1
else:
return n * factorial(n-2)
reduce(lambda x,y: y*x, range(n,1,-2))
Which is basically the same as the simple iterative version:
x = n
for y in range(n-2, 1, -2):
x*=y
Obviously you can also do it recursively, but what's the point ? This kind of example implemented using recursivity are fine when using all recursive languages, but with imperative language it's always making simple tools like recursivity looking more complex than necessary, while recursivity can be a real simplifier when dealing with fundamentally recursive structures like trees.
def doublefactorial(n):
if n <= 0:
return 1
else:
return n * doublefactorial(n-2)
That should do it. Unless I'm misunderstanding

Categories