complicated variable assignment - python

I usually do my incrementation this way:
n=0
n=n+1 # and never do n+=1
Now there is code that I am trying to comprehend and I'm struggling to understand it.
sum=0
temp = num
while temp > 0:
digit = temp % 10
# below is the line I do not understand
sum += digit ** power # what is happening here?. with power= len(str(num))
temp //= 10
if num == sum:
print num
This snippet is a piece to list the armstrong numbers.

In python ** is the sign for exponent, so x ** 2 is x^2 (or x squared).
x += g is the same as x = x + g
sum += digit ** power == sum = sum + (digit ** power)

while temp > 0:
digit = temp % 10
sum += digit ** power
temp //= 10
Take the last digit of temp
Add to sum the digit to the power of power
Delete the last digit of temp

suppose num = 34, then power becomes 2, so, for first iteration:
digit = 4
sum = 0 + 4 ** 2 # which is 0 + 16 = 16. Then adding to sum
so, digit ** power is digit to the power of 2
similarly, for second iteration:
digit = 3
sum = 16 + 3 ** 2 # which is 16 + 9 = 25

Related

Excluding a digit in a for loop

Hi I would like to exclude any number that contains a 7 from the range of 1-1000 in my for loop.
This is the code I have so far
sum = 0
for i in range(1,1001):
if #digit contains a 7:
continue
sum = sum + 1/i
return sum
Here's one way to do it by isolating each of the 3 possible digits in your range:
sum = 0
for i in range(1,1001):
if 7 not in (i-10*(i//10), i//10-10*(i//100), i//100-10*(i//1000)):
sum = sum + 1/i
print(sum)
Output:
6.484924087833117
UPDATE: To generalize for an arbitrary top number other than 1001, you could do this:
sum = 0
top = 1001
tens, temp = [1], 1001
while temp > 0:
tens.append(tens[-1] * 10)
temp //= 10
for i in range(1,top):
digits = [i // tens[j] - 10 * (i // tens[j + 1]) for j in range(len(tens) - 1)]
if 7 not in digits:
sum = sum + 1/i
print(sum)
As suggested in comments by #Lukas Schmid, this also works and may be preferable (it's certainly easier to read):
sum = 0
top = 1001
tens, temp = [1], 1001
while temp > 0:
tens.append(tens[-1] * 10)
temp //= 10
for i in range(1,top):
digits = [i // tens[j] % 10 for j in range(len(tens) - 1)]
if 7 not in digits:
sum = sum + 1/i
print(sum)
One of the simplest way to achieve that without using lots of maths, is to treat the number as a string and compare it to the char '7':
sum = 0
for i in range(1, 1000):
if '7' in str(i):
continue
sum += 1/i
return sum
Also, note that the return statment should be outside the for loop.

python Find the sum of all multiples of n below m

Find the sum of all multiples of n below m
Keep in Mind n and m are natural numbers (positive integers) m is
excluded from the multiples
sumMul(2, 9) ==> 2 + 4 + 6 + 8 = 20
sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30
sumMul(4, -7) ==> "INVALID"
I did sum of list using range(n, m, n) using n as step.
I also tried modulus to avoid range 3 args error.
I can pass many tests but cannot pass all of them.
I have tried lots of logic but to no avail. What I am doing wrong?
CODEWARS: https://www.codewars.com/kata/57241e0f440cd279b5000829/train/python
MY CODE:
def sum_mul(n, m):
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n == 0 and m == 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
Your code fails if n == 0 as then the number % n checks in the list comprehension fail, so you should check that before trying to compute the sum. Also, you could use a range with step and just do sum(range(n, m, n)). However, both ways might be too slow for some test cases with very large m.
You can do this in O(1) with the following observations:
there are (m-1) // n multiples of n below m
the sum of natural numbers from 1 to n is n*(n+1)//2
Combine those two to get the result.
Example for sumMul(3, 13) ==> 3 + 6 + 9 + 12 = 30:
(13-1) // 3 == 4 so we know there are 4 multiples of 3 below 13
those are 3 + 6 + 9 + 12 == 3 * (1 + 2 + 3 + 4)
with (2) we know 1 + 2 + 3 + 4 == 4*5//2 == 10
so the result is 10 * 3 == 30
Putting that into code and handling the special cases is left as an exercise to the interested reader.
You have one main problem, that is you should prevent the situation when n==0 and you divide it in your list comprehension. It will raise zero division error. so you should check before the validation that n is not equal to zero.
Second thing is that you need to check whether n or m are negatives, as the exercise declared both n and m should be positives.
def sum_mul(n, m):
if n==0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
sum_list = sum(my_list)
if sum_list >= 1:
return sum_list
elif n < 0 and m <= 0:
return 'INVALID'
elif n == m:
return n - m
elif n > m:
return 'INVALID'
You can just compute that result mathematically using integer divisions:
def sum_mul(n, m):
if n<1 or n>m: return "INVALID"
return m//n*(m//n+1)//2*n
First you get the number of multiple of n in m (which is merely dividing m by n ignoring the remainder) : m//n
Multiples of n will be nx1, nx2, nx3, ... up to the number of multiples. Factorizing the sum of those by n we get: n(1+2+3+ ... m//n).
The sum of numbers from 1 up to a given number x is obtained by x(x+1)/2. In this case x is the number of multiples m//n
Putting it all together we get n * x * (x+1) /2 where x is m//n, so:
n * (m//n) * (m // n + 1) // 2
You should comprove all cases before call sum function.
Like this:
def sum_mul(n, m):
if n == 0 or m == 0:
return 'INVALID'
if n == m:
return n - m
if n<0 or m<0:
return 'INVALID'
my_list = [number for number in range(n, m) if number % n == 0]
return sum(my_list)
In fact, you dont't need to create if elif structure because you are using returns, so next instruction after return not executed.

Python Arithmetic Sequence Sum

How do I make a code that follows this? 1⋅2+2⋅3+3⋅4+…+(n−1)⋅n
For example, if n=5, the answer is 1⋅2+2⋅3+3⋅4+4⋅5=40.
n cannot be less than or equal to two or more or equal to 1000
This is my code for now but it doesn't work.
n = int(input())
if n>= 2 and n<=1000:
sum = 0;
numbers = range(1, n+1)
for amount in numbers:
if (amount % 2 == 1):
sum *= amount
else:
sum += amount
print(sum)
For every number between 1 and n-1 (inclusive), you need to multiply it by the following number, and then sum them all. The easiest way to represent this is with a comprehension expression over a range call:
result = sum(i * (i + 1) for i in range(1, n))
You need to reproduce exactly the scheme you give
for each number, mulitply it with itself-1, and sum that
def compute(n):
if 2 <= n <= 1000:
total = 0
for amount in range(1, n + 1):
total += amount * (amount - 1)
print(total)
But that's the same as multiplying each with itself+1, if you change the bound to get one step less
for amount in range(1,n):
total += amount * (amount + 1)
Then you can use builtin methos sum and a generator syntax
def compute(n):
if 2 <= n <= 1000:
total = sum(nb * (nb + 1) for nb in range(1,n))
print(total)
If you try to approach it mathematically, you can have the answer in a single expression.
Dry run your code. You will see that for n = 5, you are doing as follows:
Num of Iterations = 6 (1 -> 5+1)
Iteration 1
sum = 0 + 1 = 1
Iteration 2
sum = 1 * 2 = 2
Iteration 3
sum = 2 + 3 = 5
Iteration 4
sum = 5 * 4 = 20
Iteration 5
sum = 20 + 5 = 25
Iteration 6
sum = 25 * 6 = 150
In this, you are completely disregarding the BODMAS/PEMDAS rule of multiplication over addition in the process of regenerating and calculating the series
What you need to do is
Iteration 1:
sum = 0 + 2 * 1 = 2
Iteration 2:
sum = 2 + 3 * 2 = 8
Iteration 3:
Sum = 8 + 4*3 = 20
Iteration 4:
Sum = 20 + 5*4 = 40
Here, We have broken the step as follows:
For each iteration, take the product of (n) and (n-1) and add it to the previous value
Also note that in the process, we are first multiplying and then adding. ( respecting BODMAS/PEMDAS rule )
So, you need to go from n = 2 to n = 5 and on each iteration you need to do (n-1)*(n)
As mentioned earlier, the loop is as follows:
## Checks for n if any
sum = 0
for i in range(2, n):
sum = sum + (i-1)*i
print(sum)

Calculating the sum of the 4th power of each digit, why do I get a wrong result?

I am trying to complete Project Euler question #30, I decided to verify my code against a known answer. Basically the question is this:
Find the sum of all the numbers that can be written as the sum of fifth powers of their digits.
Here is the known answer I am trying to prove with python:
1634 = 1^4 + 6^4 + 3^4 + 4^4
8208 = 8^4 + 2^4 + 0^4 + 8^4
9474 = 9^4 + 4^4 + 7^4 + 4^4
As 1 = 1^4 is not a sum it is not included.
The sum of these numbers is 1634 + 8208 + 9474 = 19316.
When I run my code I get all three of the values which add up to 19316, great! However among these values there is an incorrect one: 6688
Here is my code:
i=1
answer = []
while True:
list = []
i=i+1
digits = [int(x) for x in str(i)]
for x in digits:
a = x**4
list.append(a)
if sum(list) == i:
print(sum(list))
answer.append(sum(list))
The sum of list returns the three correct values, and the value 6688. Can anybody spot something I have missed?
You are checking the sum too early. You check for a matching sum for each individual digit in the number, and 6 ^ 4 + 6 ^ 4 + 8 ^ 4 is 6688. That's three of the digits, not all four.
Move your sum() test out of your for loop:
for x in digits:
a = x**4
list.append(a)
if sum(list) == i:
print(sum(list))
answer.append(sum(list))
At best you could discard a number early when the sum already exceeds the target:
digitsum = 0
for d in digits:
digitsum += d ** 4
if digitsum > i:
break
else:
if digitsum == i:
answer.append(i)
but I'd not bother with that here, and just use a generator expression to combine determining the digits, raising them to the 4th power, and summing:
if sum(int(d) ** 4 for d in str(i)) == i:
answer.append(i)
You haven't defined an upper bound, the point where numbers will always be bigger than the sum of their digits and you need to stop incrementing i. For the sum of nth powers, you can find such a point by taking 9 ^ n, counting its digits, then taking the number of digits in the nth power of 9 times the nth power of 9. If this creates a number with more digits, continue on until the number of digits no longer changes.
In the same vein, you can start i at max(10, 1 + 2 ** n), because the smallest sum you'll be able to make from digits will be using a single 2 digit plus the minimum number of 1 and 0 digits you can get away with, and at any power greater than 1, the power of digits other than 1 and 0 is always greater than the digit value itself, and you can't use i = 1:
def determine_bounds(n):
"""Given a power n > 1, return the lower and upper bounds in which to search"""
nine_power, digit_count = 9 ** n, 1
while True:
upper = digit_count * nine_power
new_count = len(str(upper))
if new_count == digit_count:
return max(10, 2 ** n), upper
digit_count = new_count
If you combine the above function with range(*<expression>) variable-length parameter passing to range(), you can use a for loop:
for i in range(*determine_bounds(4)):
# ...
You can put determining if a number is equal to the sum of its digits raised to a given power n in a function:
def is_digit_power_sum(i, n):
return sum(int(d) ** n for d in str(i)) == i
then you can put everything into a list comprehension:
>>> n = 4
>>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)]
[1634, 8208, 9474]
>>> n = 5
>>> [i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n)]
[4150, 4151, 54748, 92727, 93084, 194979]
The is_digit_power_sum() could benefit from a cache of powers; adding a cache makes the function more than twice as fast for 4-digit inputs:
def is_digit_power_sum(i, n, _cache={}):
try:
powers = _cache[n]
except KeyError:
powers = _cache[n] = {str(d): d ** n for d in range(10)}
return sum(powers[d] for d in str(i)) == i
and of course, the solution to the question is the sum of the numbers:
n = 5
answer = sum(i for i in range(*determine_bounds(n)) if is_digit_power_sum(i, n))
print(answer)
which produces the required output in under half a second on my 2.9 GHz Intel Core i7 MacBook Pro, using Python 3.8.0a3.
Here Fixed:
i=1
answer = []
while True:
list = []
i=i+1
digits = [int(x) for x in str(i)]
for x in digits:
a = x**4
list.append(a)
if sum(list) == i and len(list) == 4:
print(sum(list))
answer.append(sum(list))
The bug I found:
6^4+6^4+8^4 = 6688
So I just put a check for len of list.

Project Euler problem #111. Generate 10 digit primes with most repeated individual digits

I am working on project Euler problem #111. I have created this program which works fantastic for the given example but apparently is not producing the desired answer to the problem. Here's my source code in python:-
#This function generates all the primes of 4 digits with the highest repeated digits 1 to 9 and returns their sum for eg. 3313, 4441, 4111 etc.
Note that any digit from 1 to 9 can come at most of 3 times in a 4 digit prime number. I have highlighted the same in the code.`
from more_itertools import distinct_permutations
from sympy.ntheory.primetest import isprime
def fn1to9():
s = 0
for digit in range(1, 10):
for j in range(0, 10):
permutations = list(distinct_permutations(str(digit) * 3 + str(j)))
for perm in permutations:
num = int("".join(perm))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
This function is for the special case of 0. Note that 0 can come atmost 2 times in a 4 digit prime no. I have bolded the number 2 in the code.
def fnFor0():
s = 0
for firstDigit in range(1, 10):
permutations = list(distinct_permutations(str(0) *2+ str(firstDigit)))
for perm in permutations:
for msd in range(1, 10):
temp = list(perm)
temp.insert(0, str(msd))
num = int("".join(temp))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
Now, this program works well and produces the desired sum of 273700 as has been stated in the question. So, I made the required changes and ran it for 10 digits. The required changes were changing the str(digit)*3 to str(digit)*9 in fn1to9 and str(digit)*2 to str(digit)*8 in fnFor0 in the distinct_permutations() function (Hoping that 9 digits will be repeated for every digit from 1 to 9 in the prime number and 8 0s for the prime number containing 0s). But it did not give the desired answer. Then I inspected and found out that for repeated digits of 2 and 8, the maximum repetition can be of 8 digits, so I wrote another function specifically for these 2 digits which is as follows:
def fnFor2and8():
s = 0
for digit in [2,8]:
for firstDigit in range(0, 10):
for secondDigit in range(0, 10):
permutations = list(distinct_permutations(str(digit) * 8 + str(firstDigit) + str(secondDigit)))
for perm in permutations:
num = int("".join(perm))
if (num > 1000000000):
if (isprime(num)):
print(num)
s = s + num
return s
This function as expected produces the desired 10 digits numbers with 2 and 8 repeated exactly 8 times. I had hoped it summing up the results from all of these 3 functions will give me the answer but seems like I am missing some numbers. Can someone please help me point out the flaw in my reasoning or in my program. Thanks a lot in advance.
Here was the solution I came by wehn I was working on this problem:
import eulerlib
def compute():
DIGITS = 10
primes = eulerlib.list_primes(eulerlib.sqrt(10**DIGITS))
# Only valid if 1 < n <= 10^DIGITS.
def is_prime(n):
end = eulerlib.sqrt(n)
for p in primes:
if p > end:
break
if n % p == 0:
return False
return True
ans = 0
# For each repeating digit
for digit in range(10):
# Search by the number of repetitions in decreasing order
for rep in range(DIGITS, -1, -1):
sum = 0
digits = [0] * DIGITS
# Try all possibilities for filling the non-repeating digits
for i in range(9**(DIGITS - rep)):
# Build initial array. For example, if DIGITS=7, digit=5, rep=4, i=123, then the array will be filled with 5,5,5,5,1,4,7.
for j in range(rep):
digits[j] = digit
temp = i
for j in range(DIGITS - rep):
d = temp % 9
if d >= digit: # Skip the repeating digit
d += 1
if j > 0 and d > digits[DIGITS - j]: # If this is true, then after sorting, the array will be in an already-tried configuration
break
digits[-1 - j] = d
temp //= 9
else:
digits.sort() # Start at lowest permutation
while True: # Go through all permutations
if digits[0] > 0: # Skip if the number has a leading zero, which means it has less than DIGIT digits
num = int("".join(map(str, digits)))
if is_prime(num):
sum += num
if not eulerlib.next_permutation(digits):
break
if sum > 0: # Primes found; skip all lesser repetitions
ans += sum
break
return str(ans)
if __name__ == "__main__":
print(compute())

Categories

Resources