how to calculate the given factorial equation of huge numbers? - python

How can I find the last digit of X^(N!)?
X can go up to 10^9
N can go up to 10^18
I know how to do it when only one of them is large but not both.
ps: execution time is 1 sec

I have no proof for this but...
Let's assume our target function is:
import math
def pow_fact_mod_last_digit_exact(x, y):
return pow(x, math.factorial(y), 10)
but for large values of x and y this would just take too long.
This is actually equivalent to:
import math
def pow_fact_mod_last_digit(x, y):
return pow(x, math.factorial(min(y, 4)), 10)
To test it for the first few hundred numbers:
print(all(
pow_fact_mod_last_digit(x, y) == pow_fact_mod_last_digit_exact(x, y)
for x in range(-300, 300) for y in range(300)))
# True
How did I went for it (empirically)
Let us just observe how pow(x, y, 10) behaves for some values of x and y:
n = 20 # x
m = 24 # y
print(f'{"":2s}', end=' ')
for y in range(m):
print(f'{y:2d}', end=' ')
print()
for x in range(n):
print(f'{x:2d}', end=' ')
for y in range(m):
print(f'{pow(x, y, 10):2d}', end=' ')
print()
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
2 1 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8
3 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7
4 1 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4
5 1 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
6 1 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
7 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3
8 1 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2
9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9
10 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0
11 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
12 1 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8 6 2 4 8
13 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7 1 3 9 7
14 1 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4 6 4
15 1 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5 5
16 1 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6 6
17 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3 1 7 9 3
18 1 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2 6 8 4 2
19 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9 1 9
So, it looks like to get pow(x, y, 10) you only need you only need to know x % 10 (of course) and (y - 1) % 4.
Now, the factorial of a number factorial(n) % k is 0 for n > k and we only need to take care, at most, for the case of n <= k.
For the case of k = 4, we have:
import math
print([(i, math.factorial(i) % 4) for i in range(10)])
# [(0, 1), (1, 1), (2, 2), (3, 2), (4, 0), (5, 0), (6, 0), (7, 0), (8, 0), (9, 0)]
So we do not need to worry for values of y above 4 as they will behave like 4.
EDIT: Apparently this is obvious from Fermat's Little Theorem (but it was not obvious to me O:-) ) and #OneLyner's answer contain essentially the same observations as above, as well as the reference to the theorem in the comments.

Use the fact that
pow(x, k, 10) = pow(x % 10, 1 + (k-1) % 4, 10)
You just need to know the factorial modulo 4.
And obviously, N > 3 => N! % 4 == 0, which should make your life easy.

Related

irregular spaces making pattern abnormal

I have a pattern which i printed using below code
Code :
n=5
def pyramidupdown(n):
cnt=0
space=2
lst= [str(row) for row in reversed(range(1,n+1))]
for i in range(1,n+1):
if i == 1:
s=' '.join(lst)
print(s)
else:
lst[cnt]=' '
s=' '.join(lst)
print(s)
cnt = cnt + 1
It prints the pattern below as output :
5 4 3 2 1
4 3 2 1
3 2 1
2 1
1
But my issue is with spaces when the n value is defined 2 digit like 15
the pattern is not printed properly
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
13 12 11 10 9 8 7 6 5 4 3 2 1
12 11 10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
7 6 5 4 3 2 1
6 5 4 3 2 1
5 4 3 2 1
4 3 2 1
3 2 1
2 1
1
Expected output :
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1
14 13 12 11 10 9 8 7 6 5 4 3 2 1
13 12 11 10 9 8 7 6 5 4 3 2 1
12 11 10 9 8 7 6 5 4 3 2 1
11 10 9 8 7 6 5 4 3 2 1
10 9 8 7 6 5 4 3 2 1
9 8 7 6 5 4 3 2 1
8 7 6 5 4 3 2 1
7 6 5 4 3 2 1
6 5 4 3 2 1
5 4 3 2 1
4 3 2 1
3 2 1
2 1
1
what changes do i need to make in existing code to print properly the pattern
I would just do it like this:
def pyramidupdown(n):
for i in range(n,0,-1): # loop n rows (in descending order)
lst = []
for j in range(n,0,-1): # loop n numbers (in descending order)
s = str(j)
# at the i-th row replace the first i string numbers
# (i.e. where j > i)
# by as many spaces as there are characters in that string
if j <= i:
lst.append(s)
else:
lst.append(' '*len(s))
print(" ".join(lst))
you can even make it a 1-liner (just for the fun):
def pyramidupdown(n):
print('\n'.join([" ".join([str(j) if j <= i else ' '*len(str(j)) for j in range(n,0,-1)]) for i in range(n,0,-1)]))
Now that I understand your code: here's the minimal tweak to make it work:
def pyramidupdown(n):
cnt=0
lst= [str(row) for row in reversed(range(1,n+1))]
for i in range(1,n+1):
if i == 1:
s=' '.join(lst)
print(s)
else:
lst[cnt]=' '*len(lst[cnt]) # here replace by correct number of spaces
s=' '.join(lst)
print(s)
cnt = cnt + 1

Python Reduce conditional expression

I have 9 variables a,b,c,d,e,f,g,h,i and I loop them inside 9 for loop from 0 to 9. But the range may vary.
I want all sequences of them abcdefghi, such that there is no repeated number.
Right now I have this, below:
for a in range(0, 9):
for b in range(0,9): #it doesn't have to start from 0
....
for i in range(0, 9):
if a != b and a != c ... a != i
b != c and b != d ... b != i
c != d and c != e ... c != i
... h != i:
print (a,b,c,d,e,f,g,h,i)
There are 9! = 362880 of them,
But how can I reduce the conditional expression? And what if the ranges for the for loops are different?
Thanks in advance!
You can simply do this with the itertools module:
from itertools import permutations
for arrangement in permutations('abcdefghi', 9):
print ''.join(arrangement)
from itertools import permutations
for perm in permutations(range(1, 10), 9):
print(" ".join(str(i) for i in perm))
which gives
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 9 8
1 2 3 4 5 6 8 7 9
1 2 3 4 5 6 8 9 7
1 2 3 4 5 6 9 7 8
1 2 3 4 5 6 9 8 7
# ... etc - 9! = 362880 permutations
what if i want sequence of abcdefghi such taht a,b,c,e,g is value from 0 to 9, and d,f,h,i in the range of 1 to 5
This is a bit more complicated, but still achievable. It is easier to pick the values in d..i first:
from itertools import permutations
for d,f,h,i,unused in permutations([1,2,3,4,5], 5):
for a,b,c,e,g in permutations([unused,6,7,8,9], 5):
print(a,b,c,d,e,f,g,h,i)
which gives
5 6 7 1 8 2 9 3 4
5 6 7 1 9 2 8 3 4
5 6 8 1 7 2 9 3 4
5 6 8 1 9 2 7 3 4
5 6 9 1 7 2 8 3 4
5 6 9 1 8 2 7 3 4
5 7 6 1 8 2 9 3 4
5 7 6 1 9 2 8 3 4
5 7 8 1 6 2 9 3 4
5 7 8 1 9 2 6 3 4
# ... etc - 5! * 5! = 14400 permutations
For the general case (ie Sudoku) you need a more general solution - a constraint solver like python-constraint (for intro see the python-constraint home page).
Then your solution starts to look like
from constraint import Problem, AllDifferentConstraint
p = Problem()
p.addVariables("abceg", list(range(1,10)))
p.addVariables("dfhi", list(range(1, 6)))
p.addConstraint(AllDifferentConstraint())
for sol in p.getSolutionIter():
print("{a} {b} {c} {d} {e} {f} {g} {h} {i}".format(**sol))
which gives
9 8 7 4 6 3 5 2 1
9 8 7 4 5 3 6 2 1
9 8 6 4 7 3 5 2 1
9 8 6 4 5 3 7 2 1
9 8 5 4 6 3 7 2 1
9 8 5 4 7 3 6 2 1
9 7 8 4 5 3 6 2 1
9 7 8 4 6 3 5 2 1
9 7 6 4 8 3 5 2 1
9 7 6 4 5 3 8 2 1
9 7 5 4 6 3 8 2 1
# ... etc - 14400 solutions

Nested Loops Python

Hi I am working with nested loops but can not figure out a way to start a new row for my nested loop below:
for i in range(0,10):
for j in range(10):
print(i,end =" ")
Output
0 0 0 0 0 0 0 0 0 0 1 1 1 1 1 1 1 1 1 1 2 2 2 2 2 2 2 2 2 2 3 3 3 3 3 3 3 3 3 3 4 4 4 4 4 4 4 4 4 4 5 5 5 5 5 5 5 5 5 5 6 6 6 6 6 6 6 6 6 6 7 7 7 7 7 7 7 7 7 7 8 8 8 8 8 8 8 8 8 8 9 9 9 9 9 9 9 9 9 9
The output I want is:
0 0 0 0 0 0 0 0 0 0
1 1 1 1 1 1 1 1 1 1
2 2 2 2 2 2 2 2 2 2
and so on
Thank you but I found the answer!
for i in range(0,10):
for j in range(10):
print(i, end=" ")
print()
This (and minor variations) also work:
for i in range(10):
print((('%s '%i)*10)[:-1])

How can I print this?

I am trying to teach myself python using interactivepython.org. I have come across a problem that I can not figure out. I have the slope and the spacing correct. I need it to print one less number every time. Could anybody help a newbie out?...
The code I have written:
numLines = 10
for i in range(numLines):
for k in range(i):
print(' ', end = ' ')
for j in range(1, numLines):
print(j, end = ' ')
print()
print(" ")
Prints:
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
1 2 3 4 5 6 7 8 9
Want to Print:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6
0 1 2 3 4 5
0 1 2 3 4
0 1 2 3
0 1 2
0 1
0
Well, The above answers are perfectly fine. But this is my way of doing things... :)
Code:
l = map(str,range(0,10))
for i in range(10):
print ' '.join(l[:len(l)-i]).rjust(20)
Output:
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6
0 1 2 3 4 5
0 1 2 3 4
0 1 2 3
0 1 2
0 1
0
Hope this helps :)
Try this:
numLines = 10
for i in range(numLines, 0, -1):
for j in range(0, numLines - i):
print " ",
for k in range(0, i):
print k,
print
How about this
numLines = 10
for i in range(numLines):
print "".join (" " for j in range(i)) + " ".join (str(j) for j in range(numLines - i))
Output
0 1 2 3 4 5 6 7 8 9
0 1 2 3 4 5 6 7 8
0 1 2 3 4 5 6 7
0 1 2 3 4 5 6
0 1 2 3 4 5
0 1 2 3 4
0 1 2 3
0 1 2
0 1
0
Never mind I figured it out. I had to decrement numLines by one inside the first for loop.

pyramid of numbers in python

Write a program that prompts the user to enter an integer from 1 to 15 and displays a pyramid, as shown in the following sample run:
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
6 5 4 3 2 1 2 3 4 5 6
7 6 5 4 3 2 1 2 3 4 5 6 7
I have the following:
num = eval(raw_input("Enter an integer from 1 to 15: "))
if num < 16:
for i in range(1, num + 1):
# Print leading space
for j in range(num - i, 0, -1):
print(" "),
# Print numbers
for j in range(i, 0, -1):
print(j),
for j in range(2, i + 1):
print(j),
print("")
else:
print("The number you have entered is greater than 15.")
This yields a misalignment for numbers greater than or equal to 10.
I have tried print(format(j, "4d")) and all the numbers become misaligned.
Any tips?
Thanks.
Use a leading space for a number ("01" - "09", "10", ...)
num = eval(raw_input("Enter an integer from 1 to 15: "))
def as_str(i):
s = ""
if i <10: s = " "
return s + str(i)
#num = 15
allrows = ""
for j in range(1,num+2):
#leading spaces
row = " "*3*(num-j+1)
#backward
for i in range(j-1,1,-1):
s = as_str(i)
row+=s + " "
#forward
for i in range(1,j):
s = as_str(i)
row+=s + " "
row +="\n"
allrows +=row
print allrows
Output
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
6 5 4 3 2 1 2 3 4 5 6
7 6 5 4 3 2 1 2 3 4 5 6 7
8 7 6 5 4 3 2 1 2 3 4 5 6 7 8
9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10
11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11
12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12
13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13
using string formatting, and it works for any value of n>=1:
num=int(raw_input())
max_width=len(" ".join(map(str,range(num,0,-1)))+" ".join(map(str,range(2,num+1))))+1
#max_width is the maximum width, i.e width of the last line
print "{0:^{1}}".format("1",max_width) #print 1 , ^ is used to place the
#string in the center of the max_width
for i in range(2,num+1): #print rest of the numbers from 2 to num
range1=range(i,0,-1)
strs1=" ".join(map(str,range1))
range2=range(2,i+1)
strs2=" ".join(map(str,range2))
print "{0:^{1}}".format(" ".join((strs1,strs2)),max_width) # use ^ again with max_width
outputs:
monty#monty-Aspire-5050:~$ python so27.py
5
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
monty#monty-Aspire-5050:~$ python so27.py
10
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
6 5 4 3 2 1 2 3 4 5 6
7 6 5 4 3 2 1 2 3 4 5 6 7
8 7 6 5 4 3 2 1 2 3 4 5 6 7 8
9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10
monty#monty-Aspire-5050:~$ python so27.py
20
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
6 5 4 3 2 1 2 3 4 5 6
7 6 5 4 3 2 1 2 3 4 5 6 7
8 7 6 5 4 3 2 1 2 3 4 5 6 7 8
9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10
11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11
12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12
13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13
14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14
15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
This is more compact solution:
num = eval(raw_input("Enter an integer from 1 to 15: "))
allrows = ""
for j in range(1,num+2):
#leading spaces
formatter = lambda x: str(x).ljust(3)
#shift to left
row = " "*4*(num+2-j)
#count backward
row+=" ".join(map(formatter, range(1,j)[-1::-1])) + " "
#count forward
row+= " ".join(map(formatter, range(2,j))) + '\n'
allrows +=row
print allrows
This code outputs:
1
2 1 2
3 2 1 2 3
4 3 2 1 2 3 4
5 4 3 2 1 2 3 4 5
6 5 4 3 2 1 2 3 4 5 6
7 6 5 4 3 2 1 2 3 4 5 6 7
8 7 6 5 4 3 2 1 2 3 4 5 6 7 8
9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9
10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10
11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11
12 11 10 9 8 7 6 5 4 3 2 1 2 3 4 5 6 7 8 9 10 11 12
This isn't a code golf entry, but it does show both bases.
Note the decimal version has 3-space indentation, and the hex version only 2-space indentation.
def triangle(n):
def indent(i):
return ' '*3*(n-(i+1))
def row(i):
lhs = ['%2d' % j for j in range(i,0,-1)]
rhs = lhs[:-1]
rhs.reverse()
return lhs+rhs
rows = [indent(i)+' '.join(row(i)) for i in range(n)]
return '\n'.join(rows)
def triangle_hex(n):
def indent(i):
return ' '*2*(n-(i+1))
def row(i):
lhs = ['%x' % j for j in range(i,0,-1)]
rhs = lhs[:-1]
rhs.reverse()
return lhs+rhs
rows = [indent(i)+' '.join(row(i)) for i in range(n)]
return '\n'.join(rows)
if __name__=='__main__':
print triangle(11)
print triangle_hex(15)
num = eval(raw_input("Enter an integer from 1 to 15: "))
if num < 16:
for i in range(1, num + 1):
# Print leading space
for j in range(num - i, 0, -1):
print(" "),
# Print numbers
for j in range(i, 0, -1):
print(format(j, "4d")),
for j in range(2, i + 1):
print(format(j, "4d")),
print
else:
print("The number you have entered is greater than 15.")
This is the cleanest and quickest way to do it:
num = 5
space = " "
for i in range(1, num+1):
for num_of_spaces in range(i+1, 1, -num):
x = (i-1)
spaces = space*(num-x)
print(spaces, end="")
for inv_rec in range(i, 1, -1):
print(inv_rec, end="")
for rec in range(1, i+1):
print(rec, end="")
print("")
Output is:
1
212
32123
4321234
543212345
65432123456
7654321234567
876543212345678
Process finished with exit code 0

Categories