Sum of even integers from a to b in Python - python

This is my code:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += [i]
return count
An example I put was print(sum_even(3,7)) and the output is 0. I cannot figure out what is wrong.

Your indentation is off, it should be:
def sum_even(a, b):
count = 0
for i in range(a, b, 1):
if(i % 2 == 0):
count += i
return count
so that return count doesn't get scoped to your for loop (in which case it would return on the 1st iteration, causing it to return 0)
(And change [i] to i)
NOTE: another problem - you should be careful about using range:
>>> range(3,7)
[3, 4, 5, 6]
so if you were to do calls to:
sum_even(3,7)
sum_even(3,8)
right now, they would both output 10, which is incorrect for sum of even integers between 3 and 8, inclusive.
What you really want is probably this instead:
def sum_even(a, b):
return sum(i for i in range(a, b + 1) if i % 2 == 0)

Move the return statement out of the scope of the for loop (otherwise you will return on the first loop iteration).
Change count += [i] to count += i.
Also (not sure if you knew this), range(a, b, 1) will contain all the numbers from a to b - 1 (not b). Moreover, you don't need the 1 argument: range(a,b) will have the same effect. So to contain all the numbers from a to b you should use range(a, b+1).
Probably the quickest way to add all the even numbers from a to b is
sum(i for i in xrange(a, b + 1) if not i % 2)

You can make it far simpler than that, by properly using the step argument to the range function.
def sum_even(a, b):
return sum(range(a + a%2, b + 1, 2))

You don't need the loop; you can use simple algebra:
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return a * (0.5 - 0.25 * a) + b * (0.25 * b + 0.5)
Edit:
As NPE pointed out, my original solution above uses floating-point maths. I wasn't too concerned, since the overhead of floating-point maths is negligible compared with the removal of the looping (e.g. if calling sum_even(10, 10000)). Furthermore, the calculations use (negative) powers of two, so shouldn't be subject by rounding errors.
Anyhow, with the simple trick of multiplying everything by 4 and then dividing again at the end we can use integers throughout, which is preferable.
def sum_even(a, b):
if (a % 2 == 1):
a += 1
if (b % 2 == 1):
b -= 1
return (a * (2 - a) + b * (2 + b)) // 4

I'd like you see how your loops work if b is close to 2^32 ;-)
As Matthew said there is no loop needed but he does not explain why.
The problem is just simple arithmetic sequence wiki. Sum of all items in such sequence is:
(a+b)
Sn = ------- * n
2
where 'a' is a first item, 'b' is last and 'n' is number if items.
If we make 'a' and b' even numbers we can easily solve given problem.
So making 'a' and 'b' even is just:
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
Now think how many items do we have between two even numbers - it is:
b-a
n = --- + 1
2
Put it into equation and you get:
a+b b-a
Sn = ----- * ( ------ + 1)
2 2
so your code looks like:
def sum_even(a,b):
if ((a & 1)==1):
a = a + 1
if ((b & 1)==1):
b = b - 1
return ((a+b)/2) * (1+((b-a)/2))
Of course you may add some code to prevent a be equal or bigger than b etc.

Indentation matters in Python. The code you write returns after the first item processed.

This might be a simple way of doing it using the range function.
the third number in range is a step number, i.e, 0, 2, 4, 6...100
sum = 0
for even_number in range(0,102,2):
sum += even_number
print (sum)

def sum_even(a,b):
count = 0
for i in range(a, b):
if(i % 2 == 0):
count += i
return count
Two mistakes here :
add i instead of [i]
you return the value directly at the first iteration. Move the return count out of the for loop

The sum of all the even numbers between the start and end number (inclusive).
def addEvenNumbers(start,end):
total = 0
if end%2==0:
for x in range(start,end):
if x%2==0:
total+=x
return total+end
else:
for x in range(start,end):
if x%2==0:
total+=x
return total
print addEvenNumbers(4,12)

little bit more fancy with advanced python feature.
def sum(a,b):
return a + b
def evensum(a,b):
a = reduce(sum,[x for x in range(a,b) if x %2 ==0])
return a

SUM of even numbers including min and max numbers:
def sum_evens(minimum, maximum):
sum=0
for i in range(minimum, maximum+1):
if i%2==0:
sum = sum +i
i= i+1
return sum
print(sum_evens(2, 6))
OUTPUT is : 12
sum_evens(2, 6) -> 12 (2 + 4 + 6 = 12)

List based approach,
Use b+1 if you want to include last value.
def sum_even(a, b):
even = [x for x in range (a, b) if x%2 ==0 ]
return sum(even)
print(sum_even(3,6))
4
[Program finished]

This will add up all your even values between 1 and 10 and output the answer which is stored in the variable x
x = 0
for i in range (1,10):
if i %2 == 0:
x = x+1
print(x)

Related

Sum of a range in Python [duplicate]

This question already has answers here:
Where to use the return statement with a loop?
(2 answers)
Closed 26 days ago.
I have to find the sum of a range between the values a and b, although either can be a negative number. If they are the same number I should just return that number. A complete beginner here. Stuck on a Code-Wars kata.
Apparently, my code returns None. I don't necessarily want the solution to the problem. I more want to know why my code is wrong. (The first line of the code is given)
def get_sum(a,b):
if a == b:
return a
num = 0
if a > b:
for i in range(a, b):
num += i
return num
elif a < b:
for i in range(b, a):
num += i
return num
I think there is an indentation issue located on the return instruction and also a problem on the sign greater than.
def get_sum(a,b):
if a == b:
return a
num = 0
if a < b:
for i in range(a, b):
num += i
return num
elif a > b:
for i in range(b, a):
num += i
return num
You could also use built-in functions to make it faster and more concise
sum(range(a, b))
Thinking about the problem itself, rather than your particular function, you could use Gauss's method: reverse the sequence, add it to itself, and the total will be twice the sum sought.
However, each term is now equal, so you have reduced the question to a multiplication.
1 + 2 + 3 + 4
4 + 3 + 2 + 1
-------------
5 + 5 + 5 + 5 = 20
20/2 = 10
In Python this would be:
def get_sum(small, large):
return int((large - small + 1) * (small + large) / 2)
You can use the gauss formula:
n(n+1)/2
https://letstalkscience.ca/educational-resources/backgrounders/gauss-summation
def gauss(n):
return (abs(n)*(abs(n)+1)/2)* (-1 if n < 0 else 1)
def sum_between(a, b):
a,b = min(a, b), max(a, b)
return gauss(b) - gauss(abs(a))
You can actually transform sum_between in a single formula with a bit of algebra.
For the same number then just add an if
There's always
def get_sum(a, b):
return sum(range(min(a, b), max(a, b)))
add 1 to the lower-bound if you want numbers strictly between, or add 1 to the upper bound if you want it included in the sum.
It might not be as pedagogical as writing it out yourself and it doesn't rely on math(s).

Improving performance of finding out how many possible triangles can be made with a given stick

I am doing an assessment that is asking by the given "n" as input which is a length of a stick; how many triangles can you make? (3 < n < 1,000,000)
For example:
input: N=8
output: 1
explanation:
(3,3,2)
input: N=12
output: 3
explanation:
(4,4,4) (4,5,3) (5,5,2)
Now the codes I wrote are returning 33 % accuracy as the web assessment is throwing time limit error.
ans = 0
n = int(input())
for a in range(1, n + 1):
for b in range(a, n - a + 1):
c = n - a - b
if a + b > c >= b:
ans += 1
print(ans)
code b:
ans = 0
n = int(input())
for i in range(1,n):
for j in range(i,n):
for c in range(j,n):
if(i+j+c==n and i+j>c):
ans+=1
print(ans)
How can this be made faster?
This is an intuitive O(n) algorithm I came up with:
def main():
n = int(input())
if n < 3:
print(0)
return
ans = n % 2
for a in range(2, n//2+1):
diff = n - a
if diff // 2 < a:
break
if diff % 2 == 0:
b = diff // 2
else:
b = diff // 2 + 1
b = max(b - a // 2, a)
c = n - b - a
if abs(b - c) >= a:
b += 1
c -= 1
ans += abs(b-c)//2 + 1
print(ans)
main()
I find the upper bound and lower bound for b and c and count the values in that range.
I thought of a completely different way to do it:
We take the smallest side and call it a. It can never be more than n/3, otherwise a different side would be the smallest.
We try to figure out what is the next smallest side (b):
We see what's left after reducing our a.
We divide it by 2 in order to find the middle where we'll start advancing from
We'll see how far we can get before the difference between the lengths is a (or the difference from the middle is a/2) as that's the minimum b side length that is possible and satisfies a+b>c. Basically, the second smallest side is a/2 less than the middle.
The smallest side is the maximum between our calculation or a, in caseb==a. b can never be lower than a as it violates our first rule that a is the smallest.
We figure out the difference from the middle and the smallest side. That's how many possible solutions we have for the other 2 sides.
Add everything together for every a and that's our solution.
The floor, ceil and % are fixes for when a is odd, the middle is .5, or +1 in case b+c is even, cause b==c is then possible.
Code:
import math
n = int(input("Enter a number: "))
total = 0
# a is the shortest side
for a in range(1, (n//3)+1):
length_left = n-a
middle_number = length_left/2
# Shortest potential side b where the distance between b and c is smaller than a (c-b < a)
b = middle_number-(math.ceil(a/2)-1)-((length_left % 2)/2)
# We calculate how far it is from the middle
max_distance_from_middle = middle_number - max(b, a)
# Add another 1 if the length is even, in case b==c
adding = math.floor(max_distance_from_middle) + (1 if length_left % 2 == 0 else 0)
total += adding
print(total)
Or in an ugly one-liner:
n = int(input("Enter a number: "))
print(sum(math.floor((n-a)/2 - max((n-a)/2 - math.ceil(a/2) + 1 - (((n-a) % 2)/2), a)) + 1 - ((n-a) % 2) for a in range(1, (n//3)+1)))
Alcuin's sequence expansion: O(1)
Alcuin's sequence [See: https://en.wikipedia.org/wiki/Alcuin%27s_sequence] is a series expansion of the polynomial below, where the nth coefficient corresponds to the nth answer, that is, the maximum amount of unique integer triangles with perimeter n.
The algorithmic implementation of this is simply a formula. The Online Encyclopaedia of Integer Sequences (OEIS) provides many formulas that achieve this, the simplest of which is:
round(n^2 / 48) (Even)
round((n+3)^2 / 48) (Odd)
[See: https://oeis.org/A005044]
This evidently has a constant time complexity, given that the only functions required are modulo 2, integer squared and round, each of which are constant time (under certain definitions).
Implementation
Expanded:
def triangles(n):
if n % 2 == 0:
return round(n ** 2 / 48)
else:
return round((n + 3) ** 2 / 48)
1-Liner:
def triangles(n): return round(n ** 2 / 48) if n%2==0 else round((n + 3) ** 2 / 48)
Or even:
def triangles(n): return round((n + 3 * n%2) ** 2 / 48)
Extra
No imports are needed.
As the OP questioned, why do we divide by 48? While I can't answer that explicitly, let's get an intuitive understanding. We are squaring numbers, so it is evidently going to expand greatly. By the time we get to 5, that would give 64 (8^2). So, there must be a constant (albeit a reciprocal) to restrict the growth of the parabola, thus the / 48.
When we graph the OP's method, it gives an alternating parabola. This explains why there is a back-and-forth with the +3 and +0.
https://mathworld.wolfram.com/AlcuinsSequence.html
import math
n = int(input())
print(round(n ** 2 / 48)) if n % 2 == 0 else print(round((n + 3)** 2 / 48))

How return works in recursion?

def sum_it(n,y):
if n ==0:
return y
else:
return sum_it(n-1,n+y)
required output for sum_it(3,4)i.e. (3+2+1)+4 must be 10
but obtained output is 5
Please how the return really works ?
Altough unclear, it seems like what you need when calling sum_it(n,y) is the sum of natural numbers from 1 to n plus y.
This initial sum is also known as "nth" triangular number.
If that's the case, you actually don't need recursion:
def sum_it(n,y):
return (n*(n+1))//2 + y
If recursion is a must:
def sum_it(n,y):
if (n > 1):
return n + sum_it(n-1,y)
return n + y
Feel free to ask if any doubt remains.
If you intended to sum like (3+2+1) + 4, this code will works.
def sum_it(n,y):
if( n == 1):
return y + 1
else:
return(n + sum_it(n-1,y))
For example, sum_it(3,4) works like below
sum_it(3,4) returns 3 + sum_it(2,4)
sum_it(2,4) returns 2 + sum_it(1,4)
sum_it(1,4) returns 1 + 4
It means
sum_it(3,4) returns 3 + 2 + 1 + 4

Define a function to choose 2 bigger number out of 3 numbers then sum the square of the 2 numbers

Define a function that takes three numbers as arguments and returns the sum of the squares of the two larger numbers.
For example, given 6,7,8, the function that I defined should return 113
When I gave my code, it solves most of the problems but apparently there is some possibility that I haven't tried?? I think my code is flawed but not sure what other possibilities are there. Would really appreciate some help thank you so much!
def bigger_sum(a,b,c):
if(a+b>b+c):
return(a*a+b*b)
if(a+c>b+c):
return(a*a+c*c)
if(b+c>a+c):
return(b*b+c*c)
You can use min for this problem:
def big2_sqrsum(a,b,c):
x = min(a,b,c)
return (a*a + b*b + c*c) - (x*x)
print(big2_sqrsum(6,7,8))
Output:
113
Alternate solution with if-else
def big2_sqrsum2(a,b,c):
if a < b and a <c:
return b*b + c*c
elif b < a and b < c:
return a*a + c*c
elif c < a and c < b:
return a*a + b*b
Just check for the smallest number. That known, assign the values to two new variables that will hold the largest and second largest value and sum their squares.
Something like this :
big1 = 0
big2 = 0
if ([a is smallest]):
big1 = b
big2 = c
elif ([b is smallest]):
big1 = a
big2 = c
elif ([c is smallest]):
big1 = a
big2 = b
allows you to have only one place to calculate your formula :
return big1 * big1 + big2 * big2
Let's take a look at why your code is flawed. Given a comparison like if a + b > b + c:, the implication that both a and b are both greater than c is false. b can be the smallest number. All you know is that a > c, since you can subtract b from both sides of the inequality.
You need to find and discard the smallest number. The simplest way is to compute the minimum with min and subtract it off, as #Sociopath's answer suggests.
If you want to keep your if-elsestructure, you have to compare numbers individually:
if a > b:
n1= a
n2 = b if b > c else c
elif a > c:
n1, n2 = a, b
else:
n1, n2 = b, c
You can Simply Define Function With Using min()
def two_bigger_sum(num1,num2,num3):
min_num = min(num1,num2,num3) # it returns minimum number
return ((num1**2 + num2**2 + num3**2)-(min_num**2)) # num**2 = square of num
print(two_bigger_sum(6,7,8))
Output = 113
Sociopath's answer works, but is inefficient since it requires two extra floating point multiplies. If you're doing this for a large number of items, it will take twice as long! Instead, you can find the two largest numbers directly. Basically, we're sorting the list and taking the two largest, this can be directly as follows:
def sumsquare(a,b,c):
# Strategy: swap, and make sure c is the smallest by the end
if c > b:
b, c = c, b
if c > a:
a, c = c, a
return a**2 + b**2
# Test:
print(sumsquare(3,1,2))
print(sumsquare(3,2,1))
print(sumsquare(1,2,3))
print(sumsquare(1,3,2))
print(sumsquare(2,1,3))
print(sumsquare(2,3,2))
I have tried to use list comprehension & list slicing with sorting method.
def b2(l):
return sum([x**2 for x in sorted(l)[1:]])
print(b2([1,2,3]))
OP:-
13

How to find sum of cubes of the divisors for every number from 1 to input number x in python where x can be very large

Examples,
1.Input=4
Output=111
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
------------------------
sum = 111(output)
1.Input=5
Output=237
Explanation,
1 = 1³(divisors of 1)
2 = 1³ + 2³(divisors of 2)
3 = 1³ + 3³(divisors of 3)
4 = 1³ + 2³ + 4³(divisors of 4)
5 = 1³ + 5³(divisors of 5)
-----------------------------
sum = 237 (output)
x=int(raw_input().strip())
tot=0
for i in range(1,x+1):
for j in range(1,i+1):
if(i%j==0):
tot+=j**3
print tot
Using this code I can find the answer for small number less than one million.
But I want to find the answer for very large numbers. Is there any algorithm
for how to solve it easily for large numbers?
Offhand I don't see a slick way to make this truly efficient, but it's easy to make it a whole lot faster. If you view your examples as matrices, you're summing them a row at a time. This requires, for each i, finding all the divisors of i and summing their cubes. In all, this requires a number of operations proportional to x**2.
You can easily cut that to a number of operations proportional to x, by summing the matrix by columns instead. Given an integer j, how many integers in 1..x are divisible by j? That's easy: there are x//j multiples of j in the range, so divisor j contributes j**3 * (x // j) to the grand total.
def better(x):
return sum(j**3 * (x // j) for j in range(1, x+1))
That runs much faster, but still takes time proportional to x.
There are lower-level tricks you can play to speed that in turn by constant factors, but they still take O(x) time overall. For example, note that x // j == 1 for all j such that x // 2 < j <= x. So about half the terms in the sum can be skipped, replaced by closed-form expressions for a sum of consecutive cubes:
def sum3(x):
"""Return sum(i**3 for i in range(1, x+1))"""
return (x * (x+1) // 2)**2
def better2(x):
result = sum(j**3 * (x // j) for j in range(1, x//2 + 1))
result += sum3(x) - sum3(x//2)
return result
better2() is about twice as fast as better(), but to get faster than O(x) would require deeper insight.
Quicker
Thinking about this in spare moments, I still don't have a truly clever idea. But the last idea I gave can be carried to a logical conclusion: don't just group together divisors with only one multiple in range, but also those with two multiples in range, and three, and four, and ... That leads to better3() below, which does a number of operations roughly proportional to the square root of x:
def better3(x):
result = 0
for i in range(1, x+1):
q1 = x // i
# value i has q1 multiples in range
result += i**3 * q1
# which values have i multiples?
q2 = x // (i+1) + 1
assert x // q1 == i == x // q2
if i < q2:
result += i * (sum3(q1) - sum3(q2 - 1))
if i+1 >= q2: # this becomes true when i reaches roughly sqrt(x)
break
return result
Of course O(sqrt(x)) is an enormous improvement over the original O(x**2), but for very large arguments it's still impractical. For example better3(10**6) appears to complete instantly, but better3(10**12) takes a few seconds, and better3(10**16) is time for a coffee break ;-)
Note: I'm using Python 3. If you're using Python 2, use xrange() instead of range().
One more
better4() has the same O(sqrt(x)) time behavior as better3(), but does the summations in a different order that allows for simpler code and fewer calls to sum3(). For "large" arguments, it's about 50% faster than better3() on my box.
def better4(x):
result = 0
for i in range(1, x+1):
d = x // i
if d >= i:
# d is the largest divisor that appears `i` times, and
# all divisors less than `d` also appear at least that
# often. Account for one occurence of each.
result += sum3(d)
else:
i -= 1
lastd = x // i
# We already accounted for i occurrences of all divisors
# < lastd, and all occurrences of divisors >= lastd.
# Account for the rest.
result += sum(j**3 * (x // j - i)
for j in range(1, lastd))
break
return result
It may be possible to do better by extending the algorithm in "A Successive Approximation Algorithm for Computing the Divisor Summatory Function". That takes O(cube_root(x)) time for the possibly simpler problem of summing the number of divisors. But it's much more involved, and I don't care enough about this problem to pursue it myself ;-)
Subtlety
There's a subtlety in the math that's easy to miss, so I'll spell it out, but only as it pertains to better4().
After d = x // i, the comment claims that d is the largest divisor that appears i times. But is that true? The actual number of times d appears is x // d, which we did not compute. How do we know that x // d in fact equals i?
That's the purpose of the if d >= i: guarding that comment. After d = x // i we know that
x == d*i + r
for some integer r satisfying 0 <= r < i. That's essentially what floor division means. But since d >= i is also known (that's what the if test ensures), it must also be the case that 0 <= r < d. And that's how we know x // d is i.
This can break down when d >= i is not true, which is why a different method needs to be used then. For example, if x == 500 and i == 51, d (x // i) is 9, but it's certainly not the case that 9 is the largest divisor that appears 51 times. In fact, 9 appears 500 // 9 == 55 times. While for positive real numbers
d == x/i
if and only if
i == x/d
that's not always so for floor division. But, as above, the first does imply the second if we also know that d >= i.
Just for Fun
better5() rewrites better4() for about another 10% speed gain. The real pedagogical point is to show that it's easy to compute all the loop limits in advance. Part of the point of the odd code structure above is that it magically returns 0 for a 0 input without needing to test for that. better5() gives up on that:
def isqrt(n):
"Return floor(sqrt(n)) for int n > 0."
g = 1 << ((n.bit_length() + 1) >> 1)
d = n // g
while d < g:
g = (d + g) >> 1
d = n // g
return g
def better5(x):
assert x > 0
u = isqrt(x)
v = x // u
return (sum(map(sum3, (x // d for d in range(1, u+1)))) +
sum(x // i * i**3 for i in range(1, v)) -
u * sum3(v-1))
def sum_divisors(n):
sum = 0
i = 0
for i in range (1, n) :
if n % i == 0 and n != 0 :
sum = sum + i
# Return the sum of all divisors of n, not including n
return sum
print(sum_divisors(0))
# 0
print(sum_divisors(3)) # Should sum of 1
# 1
print(sum_divisors(36)) # Should sum of 1+2+3+4+6+9+12+18
# 55
print(sum_divisors(102)) # Should be sum of 2+3+6+17+34+51
# 114

Categories