I have written this piece of code that implements the double factorial in Python both iteratively and recursively; the code works without problems, but I'm interested in improving my overall programming style. Here's the code:
def semif_r(n): #recursive implementation
if n == 0 or n == 1:
z = 1
else:
z= n * semif_r(n-2)
return z
def semif_i(n): #iterative implementation
N = 1
if n == 0 or n == 1:
return 1
elif n%2 == 1:
for i in range(0,n/2):
N = (2*i + 1)*N
VAL = N
return n*VAL
elif n%2 == 0:
for i in range(0,n/2):
N = (2*i+2)*N
VAL = N
return VAL
I hope that some experienced programmers can give me some feedback about improving my code!
from operator import mul
semif_pythonic = lambda x: reduce(mul, xrange(x, 1, -2))
I don't really understand why you need the VAL variable since it is equal to N; just use N.
You may write: N *= (2*i + 1) rather than N = (2*i + 1)*N but if you don't want to use this way, maybe it would still be better to write N = N * (2*i + 1) because it is easier to read.
For arithmetic functions, write n//2 rather than n/2 because both are different in Python 3; writing n//2 is more portable accross the different versions of Python.
As a challenge, you may want to try writing a third version as a tail-recursive function by using the tco module: http://baruchel.github.io/python/2015/11/07/explaining-functional-aspects-in-python/
Related
I tried to write my own power() function in python but when i compared it with python inbuilt pow() function in output and speed. I found that my code is 6-7 times slower and last 3-4 digits of output is different as compared to output of inbuilt pow() function for floating point numbers. I am totally new to python and unable to find the explanation. plz help
Note:- I have used binomial expansion for calculating fractional power and Binary Exponent for integral power
Here is my code-
def power(x, n):
if not(isinstance(x, complex) or isinstance(n, complex)):
res = 1
if n == 0 and x != 0:
return 1
if n > 0 and x == 0:
return 0
if n < 0 and x == 0:
return "Zero Division Error"
if n == 0 and x == 0:
return "Indeterminate Form"
if n == 1:
return x
if n > 0 and n < 1:
return fpower(x,n)
if n > 1 and n < 2:
return x*fpower(x,n-1)
if n == -1:
return 1/x
if n < 0 and n > -1:
return fpower(x,n)
if n < -1 and n > -2:
return 1/x*fpower(x,n+1)
if n >= 2:
f_p = n - n // 1
t_x = x
n //= 1
if n%2:
res = x
n //= 2
else:
res = 1
n //= 2
while n != 1 and n > 1:
if n%2:
res *= x*x
x *= x
n //= 2
res *= x*x
if f_p == 0:
return res
elif f_p < 1:
return res*fpower(t_x,f_p)
if n <= -2:
f_p = n+(-n // 1)
t_x = x
n = -n // 1
if n%2:
res = 1/x
n = n // 2
else:
res = 1
n = n // 2
while n != 1 and n > 1:
if n%2:
res *= 1/x*1/x
x *= x
n //= 2
res *= 1/x*1/x
if f_p == 0:
return res
elif f_p > -1:
return res*fpower(t_x,f_p)
#function to calculate fractional power
def fpower(x, n):
pwr = 0
sign = 1
t_n = n
if x < 0:
x *= -1
sign = -1
while x > 2:
x = x/2
pwr += 1
if x >1:
pwr *= n
n *= -1
x = 1/x-1
elif x < 0.5 and x != 0:
x = sign*1/x
return fpower(x,-n)
elif x != 0:
x -= 1
res = 0
step = 1
coeff = 1
i = 0
while step > 1e-20:
step = coeff*power(x,i)
res += step
coeff *= (n-i)/(i+1)
i += 1
if step < 0:
step *= -1
mp = res*power(2,pwr)
if sign < 0:
pi = 3.141592653589793
real = mp*cos(t_n*pi)
img = mp*sin(t_n*pi)
if img != 0:
return complex(real,img)
else:
return real
else:
return mp
Output Comparison:
Inbuilt fn -
pow(89,99.354)
4.7829376579139805e+193
Own fn -
power(89,99.354)
4.7829376579139765e+193
Speed Comparison:
Inbuilt fn time -
pow(89,99.354)
0.00026869773864746094
Own fn time-
power(89,99.354)
0.0023398399353027344
There are a few things that can be said here. First of all, many Python standard library functions will be implemented in C, not in Python, so they will be faster. This makes sense, as the standard library will be called by a lot of code lots of times, so it pays off to implement such often-used code in a faster language.
Along with that goes additional optimization: this code is called so often that, besides implementing it in C, it makes sense to optimize this code. Compared to baseline Python, this includes writing "faster" C, but also what you get out of the box from your C compiler.
Some cursory research doesn't suggest this is the case, but exponentiation, as a common math operation, could also have some hardware acceleration that requires you to use specific intructions of the architecture you're running on - which you won't easily (if at all) be able to utilize in pure Python.
Then there's the matter of algorithms; once we leave the language difference aside, there are different ways to compute exponentiation, and without contrary evidence you should not assume that you have chosen the most efficient one. From you pointing out your algorithms it seems you have carefully chosen which ones to use, but still - when you're posing aquestion like this, don't simply assume you made an equally good choice as the standard library of a *looks at Wikipedia* 30 year old language.
Finally, don't forget that benchmarking methodology also plays a role in questions like this in general. a 6-7 times difference won't go away by changing your methodology, but it's worth remembering that testing your code against a very small number of inputs may not be representative of your code's performance in general, and different inputs will be representative for the built-in pow.
That's my thoughts on performance; as for accuracy, floating point errors can simply add up. As soon as you perform more than one operation on a decimal number, this will happen. (And remember, in general the first operation is representing the number in binary (IEEE 754) floating point format.) Wikipedia gives the example if squaring 0.1; 0.1 can not be represented precisely in binary, so you get your first rounding error here. As a result, squaring it will give you a less precise result than the best approximation for 0.01. As far as I can tell, you're not trying to comensate for roundign errors, and you're using a loop, so noticeable rounding errors are inevitable.
Rapid exponentiation, I need to write an algorithm that can calculate n^b faster than n multiplications! The complexity of the algorithm will be O(logn).
I have a code, I was able to pass first 20 test (I can't see the numbers), but I can't improve the algorithm to pass last 5 tests. Any suggestions how can I improve it?
def quick_power(x, n):
if n == 0:
return 1
elif n == 1:
return x
elif n == 2:
return x * x
elif n % 2 != 0:
return x * quick_power(x, n - 1)
elif n % 2 == 0:
return quick_power(x, n // 2) * quick_power(x, n // 2)
x = int(input())
n = int(input())
print(quick_power(x, n))
Your idea is in the right direction and your code is in principle not wrong. The point is that you need to distinguish two states, even and odd
if n is even: x^n = (x^(n/2))^2
if n is odd: x^n = x*x^(n-1)
, which you actually did.
Without knowing your last 5 tests, it is hard to figure out why it failed. But you can try the following simplified code.
def quick_power(x, n):
if n == 0:
return 1
elif n % 2 == 0:
return quick_power(x, n / 2)**2
else:
return x * quick_power(x, n-1)
print(quick_power(3, 5))
I was curious if any of you could come up with a more streamline version of code to calculate Brown numbers. as of the moment, this code can do ~650! before it moves to a crawl. Brown Numbers are calculated thought the equation n! + 1 = m**(2) Where M is an integer
brownNum = 8
import math
def squareNum(n):
x = n // 2
seen = set([x])
while x * x != n:
x = (x + (n // x)) // 2
if x in seen: return False
seen.add(x)
return True
while True:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
if squareNum(i) is True:
print("pass")
print(brownNum)
print(math.factorial(brownNum)+1)
break
else:
print(brownNum)
print(math.factorial(brownNum)+1)
brownNum = brownNum + 1
continue
break
print(input(" "))
Sorry, I don't understand the logic behind your code.
I don't understand why you calculate math.factorial(brownNum) 4 times with the same value of brownNum each time through the while True loop. And in the for loop:
for i in range(math.factorial(brownNum)+1,math.factorial(brownNum)+2):
i will only take on the value of math.factorial(brownNum)+1
Anyway, here's my Python 3 code for a brute force search of Brown numbers. It quickly finds the only 3 known pairs, and then proceeds to test all the other numbers under 1000 in around 1.8 seconds on this 2GHz 32 bit machine. After that point you can see it slowing down (it hits 2000 around the 20 second mark) but it will chug along happily until the factorials get too large for your machine to hold.
I print progress information to stderr so that it can be separated from the Brown_number pair output. Also, stderr doesn't require flushing when you don't print a newline, unlike stdout (at least, it doesn't on Linux).
import sys
# Calculate the integer square root of `m` using Newton's method.
# Returns r: r**2 <= m < (r+1)**2
def int_sqrt(m):
if m <= 0:
return 0
n = m << 2
r = n >> (n.bit_length() // 2)
while True:
d = (n // r - r) >> 1
r += d
if -1 <= d <= 1:
break
return r >> 1
# Search for Browns numbers
fac = i = 1
while True:
if i % 100 == 0:
print('\r', i, file=sys.stderr, end='')
fac *= i
n = fac + 1
r = int_sqrt(n)
if r*r == n:
print('\nFound', i, r)
i += 1
You might want to:
pre calculate your square numbers, instead of testing for them on the fly
pre calculate your factorial for each loop iteration num_fac = math.factorial(brownNum) instead of multiple calls
implement your own, memoized, factorial
that should let you run to the hard limits of your machine
one optimization i would make would be to implement a 'wrapper' function around math.factorial that caches previous values of factorial so that as your brownNum increases, factorial doesn't have as much work to do. this is known as 'memoization' in computer science.
edit: found another SO answer with similar intention: Python: Is math.factorial memoized?
You should also initialize the square root more closely to the root.
e = int(math.log(n,4))
x = n//2**e
Because of 4**e <= n <= 4**(e+1) the square root will be between x/2 and x which should yield quadratic convergence of the Heron formula from the first iteration on.
Take a number N and distribute it as evenly as possible among i bins.
i.e. For N distributed across i bins as [N1,N2....Ni], Σ(Na - Nb) is minimized for all a,b ∈ {0,1,..i}
I have to do this in Python. I have come up with a simplistic approach till now that works as follows:
Initial size of each bin is N/i (integer division)
Keep adding 1 to each bin in sequence from the remainder of the integer division till the remainder is exhausted.
Code:
def eq_div(N,x):
a = [N/x for i in range(x)]
rem = N%x
def eq_map(val):
global rem
if rem > 0:
rem -= 1
return val + 1
else:
return val
return map(eq_map, a)
This works but it uses the ungainly global keyword. Am I missing a library function that does this? Or can I do the same without using global?
Is there a different better solution?
Here's my attempt :) I think it's much simpler and more readable than the original and therefore easier to maintain. (I'm bigotted against functional programming, ymmv).
def pidgeon_hole(n, n_bins):
quotient = n // n_bins
remainder = n % n_bins
bins = [quotient for i in range(n_bins)]
for i in range(remainder):
bins[i] += 1
return bins
bins = pidgeon_hole(13, 3)
for bin in bins:
print(bin)
You could just loop and add 1 to each of the first rem elements of a.
Python 2.x / Python 3.x:
def eq_div(N, i):
return [] if i <= 0 else [N // i + 1] * (N % i) + [N // i] * (i - N % i)
>>> eq_div(-10, 3)
[-3, -3, -4]
You can use nonlocal instead of global in this case.
I need an explanation for the program suggested in the edit in the first answer over here. It is a program to find the totients of a range of numbers. Can somebody provide a simple explanation? (Ignore the summation part for now, I need to find out how the init method finds the totients.) I know there is an explanation in the answer, but that is an explanation for different programs, I need an explanation for this particular one.
class Totient:
def __init__(self, n):
self.totients = [1 for i in range(n)]
for i in range(2, n):
if self.totients[i] == 1:
for j in range(i, n, i):
self.totients[j] *= i - 1
k = j / i
while k % i == 0:
self.totients[j] *= i
k /= i
def __call__(self, i):
return self.totients[i]
if __name__ == '__main__':
from itertools import imap
totient = Totient(10000)
print sum(imap(totient, range(10000)))
It's a variant of the Sieve of Eratosthenes for finding prime numbers.
If you want to know the totient of a single number n, the best way to find it is to factor n and take the product of 1 less than each factor; for instance, 30 = 2 * 3 * 5, and subtracting 1 from each factor, then multiplying, gives the totient 1 * 2 * 4 = 8. But if you want to find the totients of all the numbers less than a given n, a better approach than factoring each of them is sieving. The idea is simple: Set up an array X from 0 to n, store i in each Xi, then run through the array starting from 0 and whenever Xi = i loop over the multiples of i, multiplying each by i − 1.
Further discussion and code at my blog.
I'm not completely sure what the code is doing -- but frankly it looks pretty bad. It clearly is trying to use that Euler's totient function is multiplicative, meaning that a,b are relatively prime then t(a,b) = t(a)*t(b), together with the fact that if p is a prime then t(p) = p-1. But -- it seems to be using crude trial division to determine such things. If you really want to calculate the totient of all numbers in a given range then you should use an algorithm that sieves the numbers as you go along.
Here is a version which sieves as it goes and exploits the multiplicative nature to the hilt. At each pass through the main loop it starts with a prime, p which hasn't yet been processed. It determines all powers of p <= n and then uses a direct formula for these powers (see https://en.wikipedia.org/wiki/Euler%27s_totient_function ). Once these totients have been added, it forms all possible products <= n of these powers and the numbers for which the totients have been previously computed. This gives a whole slew of numbers to add to the list of previously determined numbers. At most sqrt(n) passes need to be made through the main loop. It runs almost instantly for n = 10000. It returns a list where the ith value is the totient of i (with t(0) = 0 for convenience):
def allTotients(n):
totients = [None]*(n+1) #totients[i] will contain the t(i)
totients[0] = 0
totients[1] = 1
knownTotients = [] #known in range 2 to n
p = 2
while len(knownTotients) < n - 1:
powers = [p]
k = 2
while p ** k <= n:
powers.append(p ** k)
k +=1
totients[p] = p - 1
for i in range(1,len(powers)):
totients[powers[i]] = powers[i] - powers[i-1]
#at this stage powers represent newly discovered totients
#combine with previously discovered totients to get still more
newTotients = powers[:]
for m in knownTotients:
for pk in powers:
if m*pk > n: break
totients[m*pk] = totients[m]*totients[pk]
newTotients.append(m*pk)
knownTotients.extend(newTotients)
#if there are any unkown totients -- the smallest such will be prime
if len(knownTotients) < n-1:
p = totients.index(None)
return totients
For completeness sake, here is a Python implementation of the algorithm to compute the totient of a single number which user448810 described in their answer:
from math import sqrt
#crude factoring algorithm:
small_primes = [2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,
53,59,61,67,71,73,79,83,89,97]
def factor(n):
#returns a list of prime factors
factors = []
num = n
#first pull out small prime factors
for p in small_primes:
while num % p == 0:
factors.append(p)
num = num // p
if num == 1: return factors
#now do trial division, starting at 101
k = 101
while k <= sqrt(num):
while num % k == 0:
factors.append(k)
num = num // k
k += 2
if num == 1:
return factors
else:
factors.append(num)
return factors
def totient(n):
factors = factor(n)
unique_factors = set()
t = 1
for p in factors:
if p in unique_factors:
t *= p
else:
unique_factors.add(p)
t *= (p-1)
return t