Trying to sum numbers between numbers more efficiently - python

TLDR: Need to make code below more efficient.
I'm trying to solve a coding challenge that requires I sum all numbers between two numbers. My code shown below is passing the tests but is taking too long to run, causing me to fail due to a time out.
Is there any way to rewrite this to do the same thing in less time?
EDIT: solved, thank you so much for your solutions
def get_sum(a,b):
res = 0
if b>a:
for i in range(a,b):
res = sum(range(a,b+1))
return res
if a > b:
for i in range (b,a):
res = sum(range(b,a+1))
return res
elif a == b:
return a

a little math won't harm.
so this should work.
def get_sum(a,b):
return (b-a+1)*(a+b)/2

Maybe this?
def get_sum2(a, b):
if a == b:
return a
return sum([n for n in range(a, b+1)] if b > a else [n for n in range(b, a+1)])
if __name__=="__main__":
print(get_sum2(1, 3))

One suggestion, when you find yourself trying to check for the order of parameters do something like this so you don't have to write the same code twice:
if a>b:
a,b = b,a
# your code

Yup. Using the formula for the triangular numbers:
def get_sum(a,b):
if a > b:
b, a = a, b
sum_from_1_to_a = a * (a + 1) / 2
sum_from_1_to_b = b * (b + 1) / 2
return sum_from_1_to_b - sum_from_1_to_a
You can simplify this, obviously, but I left it this way so it is obvious how the formula is being applied.
Also, are you sure if a == b you should return a? Aren't there 0 numbers between them if they have the same value?

Related

Check if two values are both non-negative or both negative

Given a pair of integer values, I need to check if both are non-negative or both are negative.
The trivial way is:
def func(a, b):
return (a >= 0 and b >= 0) or (a < 0 and b < 0)
But I am looking for something "neater", which I believe to be possible, so I came up with this:
def func(a, b):
return (a >= 0) ^ (b >= 0) == 0
However, this one feels a little "obscure to the average reader".
Is there a cleaner way?
Multiply them and test against 0:
def func(a, b):
return a * b >= 0
This is Python. We're not about the most concise efficient possible way to do things in all cases - that's for the C++ lads to do.
If (a >= 0 and b >= 0) or (a < 0 and b < 0) is "fast enough", (which would surprise me if not the case), then stick with it. It works, and is VERY obvious what it does.
For either your second solution, or #coldspeed's, I personally would have to write some stuff down on paper to figure out what it's doing, unless the function name was a LOT better than func.

fibonacci program hangs after 40th term

I am trying to solve this problem
Each new term in the Fibonacci sequence is generated by adding the previous two terms. By starting with 1 and 2, the first 10 terms will be:
1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …
By considering the terms in the Fibonacci sequence whose values do not exceed four million, find the sum of the even-valued terms.
Link: https://projecteuler.net/problem=2
Below is the code I have to calculate a fibonacci number:
# fibonacci series
def fib(x):
if x==0 or x==1:
return 1
else:
return fib(x-1) + fib(x-2)
def test_fib(n):
for i in range (n+1):
print 'fib of', i, ' = ' , fib(i)
test_fib(41)
However, the program hangs after 40th term. What is the problem with this code and how to solve this problem for 40th and beyond terms?
A naive recursive implementation of the fibonacci algorithm will get slow really fast. There's two ways you can resolve this:
a) Switch to an iterative version
def fib(x):
if x==0 or x==1:
return 1
a = b = 1
for _ in range(x-1):
a, b = b, a+b
return b
This is less elegant than the recursive solution, but has linear time complexity.
b) Use memoization:
from functools import lru_cache
#lru_cache()
def fib(x):
if x==0 or x==1:
return 1
else:
return fib(x-1) + fib (x-2)
This is the recursive solution, but with a "memory". It has the added benefit of being even faster than the iterative version if you have to call the function many times.
In old versions of Python (e.g. 2.7), lru_cache didn't exist yet, but you implement a cheap copy that's enough for our use:
def lru_cache():
# second-order decorator to be a drop-in replacement
def decorator(fn):
cache = {}
def wrapped(*args, **kwargs):
if args in cache:
return cache[args]
val = fn(*args)
cache[args] = val
return val
return wrapped
return decorator
considering the terms in the Fibonacci sequence whose values do not
exceed four million
The 34th term exceeds four million, so you don't need beyond the 40th term. Problem solved.
A naive recursive implementation of the fibonacci algorithm will get
slow really fast. There's two ways you can resolve this:
A third approach is to use a recursive solution that isn't naive. One problem with your original is it's doubly recursive:
return fib(x-1) + fib(x-2)
Let's reduce that to a single recursion:
def fib(n, res=0, nxt=1):
if n == 0:
return res
return fib(n - 1, nxt, res + nxt)
This gets you past the 40th term, bottoming out recursion-wise at the 997th. If you need to go further, consider either #L3viathan's iteration or memoization solutions which are both excellent.
First of all here is a working Fibonacci number generator:
a,b = 0,1
print(a,b)
for x in range(0, 100):
a,b = b, a + b
print(b)
Next all you have to do is this:
a,b = 0,1
print(a,b)
for x in range(0, 100):
a,b = b, a + b
c = 0
if b % 2 == 0:
c = c + b
print(c)
The final iteration of c is your answer.
This will add your terms until a is bigger then 4 million:
def fibo(n):
i = 0
a = 1
b = 1
sumEven= 0
while i<n and a < 4000000:
print ("fib of ", i, " = ", a)
if(a % 2==0):
sumEven+=a
a,b = b, b+a
i+=1
print("sum of even: ", sumEven)
fibo(50)

Python - Modify dictionary from function

Okay, this question is a little strange, but I was wondering if I could do it like this.
I'm working on a simple Fibonacci number generator for fun since I was interested in programming it.
So I wrote this out:
def f(n):
if n == 1: return 1
if n == 2: return 2
else:
return f(n-1) + f(n-2)
and that ran very slowly, taking 15 seconds to do f(30) on my computer.
So then I wrote this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
which basically stores previous results in a dictionary like so:
{'f(1)':1,'f(2)':2,'f(3)':3,'f(4)':5} and so on. In the function it would check if that result was in that dictionary, then just use that instead of having to redo all the calculations.
This made it tons faster. I could do f(100) and it instantly appear. Going by intervals of 500, I got to f(4000) and it was still instantaneous. The one problem was that the dictionary was getting stupidly big.
So I added a = {} to the end of the function, and that didn't work; it still left a as a massive dict.
So doing this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
a = {}
didn't work. but if I do this:
def f(n):
global a
if n == 1: return 1
if n == 2: return 1
else:
if "fib(%s)" % n in a:
return a["fib(%s)" % n]
else:
z = f(n-1) + f(n-2)
a["fib(%s)" % n] = z
return z
# now run the function
f(100)
a = {}
a gets reset to an empty dictionary. Why does this happen and how can I fix it?
Your a = {} statement inside the function was never being executed; every possible path of execution reaches a return before then. If it WAS executed, you wouldn't have liked the results - it would have executed in every single recursive call to the function, meaning that your dictionary would never hold more than one item! You would somehow have to detect the outermost call and only clear the dict there, or (much simpler) clear it outside of the recursion as in your second example.
Note that much of the size of your dictionary is coming from the strange decision to use a long string key. Keying it with the number itself (as in a[n] = z) would make it much more compact.
(For future reference: the technique you've come up with here, of saving the results from previous function calls, is known as "memoization".)
Despite your question, what you really want is a faster way of calculating Fibonacci sequence, right? The problem with your original approach is that recurrence, despite being very elegant and quick to code, is quite slow. Fibonacci sequence has a close form solution. You should do this math directly to speed up your code.
As convention, consider the Fibonacci sequence F(i) as: F(0) = 0, F(1) = 1, F(k) = F(k-1) + F(k-2) k = 2, 3, ... The solution for this sequence is (I will not demonstrate it here, because is not the place for that) F(k) = (1/sqrt(5))*(a^k - b^k), where a = (1 + sqrt(5))/2 and b = (1 - sqrt(5))/2.
Thus, you code could be implemented like this:
def f(n):
a = (1 + 5**.5)/2
b = (1 - 5**.5)/2
F = (a**n - b**n)/5**.5
F = int(round(F)) #necessary to get an integer without the decimal part of the approximation. Afterall, you are working with irrational numbers.
return F
This code scale very well for large values of n.

python find GCD recursively meet error

I have two pieces of python code finding two positive integers' GCD.
Here is the correct one:
def gcdRecur(a, b):
if b == 0:
return a
return gcdRecur(b, a%b)
Here is the one with bug:
def gcdRecur(a, b):
a = max(a, b)
b = min(a, b)
if b == 0:
return a
return gcdRecur(b, a%b)
It's easy to see the differences between these two pieces of code. And I know that there is no need to add
a = max(a, b)
b = min(a, b)
before the control flow. I can't find any logic mistakes in the latter code, but it print out the wrong result.
------use former code find GCD of 182 ans 224------
print out 14
------use former code find GCD of 182 ans 224------
print out 224(wrong answer)
So I guess it may be associated with the principle of recursion in python which I don't know at all. Can anyone help me and tell me what's going on T T.
Thank you.
The problem is when you call a = max(a,b) and b is the max value, the old a will be missing, and a will equal b which leads to gcd(b,b) == b

List of numbers whose squares are the sum of two squares

I've just started learning Python and have started doing some problems just to help buid my skills however I am pretty stuck on this question.
Make a list containing all positive integers up to 1000 whose squares can be expressed as a sum of two squares, (i,e., integers p for which p^2=m^2+n^2, where m and n are integers greater than 0.)
Hints: There are several approaches. You might find it helpful to have a list of all the square numbers. The in operator might be useful.
Here's the code that I've come up with so far:
numbers=xrange(1001)
numbers_squared=[x**2 for x in numbers]
a=[]
for x in numbers_squared:
for b in numbers_squared:
if (x+b)**.5 <= 1001:
a.append(x+b)
print a
The problem I get with this is that Python takes years to do these calculations (I've waited about ten minutes and it's still printing numbers). Any hints on how to solve this would be very appreciated.
p.s. The main point is to use lists. Also hints would be more appreciated than the solution itself.
Thank You!
First of all, you aren't solving the problem. You need to do a check to make sure (x+b)**.5 is actually an integer.
Secondly, if you are printing numbers, you have already calculated out all the numbers. Doing the above will decrease the time required for this step.
how about a list comprehension?
calculate for c in range(1,1011)
for b in range (1, c)
for a in range (1, b)
as follows:
x = [(a,b,c) for c in range(1,1001) for b in range(1, c) for a in range(1,b) if a**2+b**2==c**2]
print x
I have timed this and it takes 46 seconds to complete on my computer
This might work:
def isSumOfSquares(n):
"""return True if n can be expressed as the sum of two squares; False otherwise"""
for a in xrange(1,n):
b = n-(a**2)
if b<=0:
return False
elif not math.sqrt(b)%1:
return True
return False
answer = [i for i in xrange(1,1001) if isSumOfSquares(i**2)]
Let me know if this works for you
I just answered this elsewhere!
import math
def is_triple(hypotenuse):
"""return (a, b, c) if Pythagrean Triple, else None"""
if hypotenuse < 4:
return None
c = hypotenuse ** 2
for a in xrange(3, hypotenuse):
b = math.sqrt(c - (a ** 2))
if b == int(b):
return a, int(b), hypotenuse
return None
>>> results = [x for x in range(1001) if is_triple(x)]
>>> len(results)
567
Runs almost instantly.

Categories