Problems with modulo when calculating fibonacci - python

I'm trying to solve a problem that requires me to calculate Fibonacci numbers up to 10^18 mod 10^9+7. The online judge is saying that I get right answers on the small cases (where the modulo isn't required), but in larger cases I get wrong answers.
There is no problem with the algorithm otherwise, but the memoization aka saving the results into the dictionary table seems to have failed. I have no idea why.
luku = int(input())
table = {0:0, 1:1, 2:1}
def fib(num):
if num in table:
return table[num];
if num % 2 == 0:
puoli = num / 2;
ans = (fib(puoli) * (2 * (fib(puoli + 1)) - fib(puoli))) % 1000000007;
table[num] = ans;
return ans;
else:
puoli = (num-1) / 2;
ans = (fib(puoli + 1)*fib(puoli + 1) + fib(puoli)*fib(puoli)) % 1000000007;
table[num] = ans;
return ans;
print(fib(luku))
For example, with the input 54774730983471038 I'm getting 946469205 instead of the correct answer 795317107.

Nothing wrong with memorizing.
Possibly to your surprise, the problem is that floating point precision (yeah, your numbers are truncated).
You should replace floating division operator / (single slash) with integer division operator // (double).
The following code, with the only fix mentioned above, works for me:
luku = int(input())
table = {0:0, 1:1, 2:1}
def fib(num):
if num in table:
return table[num];
if num % 2 == 0:
puoli = num // 2;
ans = (fib(puoli) * (2 * (fib(puoli + 1)) - fib(puoli))) % 1000000007;
table[num] = ans;
return ans;
else:
puoli = (num-1) // 2;
ans = (fib(puoli + 1)*fib(puoli + 1) + fib(puoli)*fib(puoli)) % 1000000007;
table[num] = ans;
return ans;
print(fib(luku))
See:
ibug#ubuntu:~ $ python3 t.py
54774730983471038
795317107

Related

Why classical division ("/") for large integers is much slower than integer division ("//")?

I ran into a problem: The code was very slow for 512 bit odd integers if you use classical division for (p-1)/2. But with floor division it works instantly. Is it caused by float conversion?
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
The full code
import random
from math import gcd
#Jacobian symbol
def Jacobian(a, n):
if (a == 0):
return 0
ans = 1
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
if (a == 1):
return ans
while (a):
if (a < 0):
a = -a
if (n % 4 == 3):
ans = -ans
while (a % 2 == 0):
a = a // 2
if (n % 8 == 3 or n % 8 == 5):
ans = -ans
a, n = n, a
if (a % 4 == 3 and n % 4 == 3):
ans = -ans
a = a % n
if (a > n // 2):
a = a - n
if (n == 1):
return ans
return 0
def solovayStrassen(p, iterations):
for i in range(iterations):
a = random.randint(2, p - 1)
if gcd(a, p) > 1:
return False
first = pow(a, int((p - 1) / 2), p)
j = (Jacobian(a, p) + p) % p
if first != j:
return False
return True
def findFirstPrime(n, k):
while True:
if solovayStrassen(n,k):
return n
n+=2
a = random.getrandbits(512)
if a%2==0:
a+=1
print(findFirstPrime(a,100))
As noted in comments, int((p - 1) / 2) can produce garbage if p is an integer with more than 53 bits. Only the first 53 bits of p-1 are retained when converting to float for the division.
>>> p = 123456789123456789123456789
>>> (p-1) // 2
61728394561728394561728394
>>> hex(_)
'0x330f7ef971d8cfbe022f8a'
>>> int((p-1) / 2)
61728394561728395668881408
>>> hex(_) # lots of trailing zeroes
'0x330f7ef971d8d000000000'
Of course the theory underlying the primality test relies on using exactly the infinitely precise value of (p-1)/2, not some approximation more-or-less good to only the first 53 most-significant bits.
As also noted in a comment, using garbage is likely to make this part return earlier, not later:
if first != j:
return False
So why is it much slower over all? Because findFirstPrime() has to call solovayStrassen() many more times to find garbage that passes by sheer blind luck.
To see this, change the code to show how often the loop is trying:
def findFirstPrime(n, k):
count = 0
while True:
count += 1
if count % 1000 == 0:
print(f"at count {count:,}")
if solovayStrassen(n,k):
return n, count
n+=2
Then add, e.g.,
random.seed(12)
at the start of the main program so you can get reproducible results.
Using floor (//) division, it runs fairly quickly, displaying
(6170518232878265099306454685234429219657996228748920426206889067017854517343512513954857500421232718472897893847571955479036221948870073830638539006377457, 906)
So it found a probable prime on the 906th try.
But with float (/) division, I never saw it succeed by blind luck:
at count 1,000
at count 2,000
at count 3,000
...
at count 1,000,000
Gave up then - "garbage in, garbage out".
One other thing to note, in passing: the + p in:
j = (Jacobian(a, p) + p) % p
has no effect on the value of j. Right? p % p is 0.

Why is my implementation of the Miller-Rabin algorithm not able to detect some primes?

I am trying to implement the Miller-Rabin primality checker for some project am working. However, the algorithm doesn't work for primes such as 101, 103, 107, 109... I can't figure out where the problem is. Thanks in advance for all the help.
def miller_rabin_is_prime(number, k=10):
if number < 2:
return False
elif number <= 3:
return True
else:
odd_num, power_of_two, factor_out = 0, 0, number - 1
while number != (2 ** power_of_two)*odd_num + 1:
if factor_out / 2 == int(factor_out / 2):
power_of_two += 1
factor_out /= 2
else:
odd_num = (number - 1) / (2 ** power_of_two)
for _ in range(k):
random = randint(2, number - 2)
checker = (random**odd_num) % number
if (checker == 1) or (checker == number - 1):
continue
try:
for loop in range(power_of_two - 1):
checker = (checker**2) % number
if checker == number - 1:
raise TypeError
except TypeError:
continue
return False
return True
I expect the output for 101 to be True, but the actual output is False.
If you replace
odd_num = (number - 1) / (2 ** power_of_two)
by
odd_num = (number - 1) // (2 ** power_of_two)
your code will work -- but fairly slowly for larger numbers. To improve the code:
Use a simpler method of computing odd_num and power_of_two
Use pow() for the modular exponentiation.
Something like:
from random import randint
def miller_rabin_is_prime(number, k=10):
if number < 2:
return False
elif number <= 3:
return True
else:
odd_num = number - 1
power_of_two = 0
while odd_num % 2 == 0:
power_of_two += 1
odd_num //= 2
for _ in range(k):
random = randint(2, number - 2)
checker = pow(random,odd_num, number)
if (checker == 1) or (checker == number - 1):
continue
try:
for loop in range(power_of_two - 1):
checker = pow(checker,2,number)
if checker == number - 1:
raise TypeError
except TypeError:
continue
return False
return True
Then, for example, miller_rabin_is_prime(1000003) will evaluate to True almost instantly, whereas your original code (even after / is replaced by //) would take about 15 seconds because of the non-modular exponentiation.
As a final remark, you are using error handling for non-error conditions (clearly there is no type error when checker == number - 1). It would be much cleaner to refactor your main loop so that it doesn't use try--except. Error handling is not meant for ordinary control flow.

Efficiently generating Stern's Diatomic Sequence

Stern's Diatomic Sequence can be read about in more details over here; however, for my purpose I will define it now.
Definition of Stern's Diatomic Sequence
Let n be a number to generate the fusc function out of. Denoted fusc(n).
If n is 0 then the returned value is 0.
If n is 1 then the returned value is 1.
If n is even then the returned value is fusc(n / 2).
If n is odd then the returned value is fusc((n - 1) / 2) + fusc((n + 1) / 2).
Currently, my Python code brute forces through most of the generation, other than the dividing by two part since it will always yield no change.
def fusc (n):
if n <= 1:
return n
while n > 2 and n % 2 == 0:
n /= 2
return fusc((n - 1) / 2) + fusc((n + 1) / 2)
However, my code must be able to handle digits in the magnitude of 1000s millions of bits, and recursively running through the function thousands millions of times does not seem very efficient or practical.
Is there any way I could algorithmically improve my code such that massive numbers can be passed through without having to recursively call the function so many times?
With memoization for a million bits, the recursion stack would be extremely large. We can first try to look at a sufficiently large number which we can work by hand, fusc(71) in this case:
fusc(71) = fusc(35) + fusc(36)
fusc(35) = fusc(17) + fusc(18)
fusc(36) = fusc(18)
fusc(71) = 1 * fusc(17) + 2 * fusc(18)
fusc(17) = fusc(8) + fusc(9)
fusc(18) = fusc(9)
fusc(71) = 1 * fusc(8) + 3 * fusc(9)
fusc(8) = fusc(4)
fusc(9) = fusc(4) + fusc(5)
fusc(71) = 4 * fusc(4) + 3 * fusc(5)
fusc(4) = fusc(2)
fusc(3) = fusc(1) + fusc(2)
fusc(71) = 7 * fusc(2) + 3 * fusc(3)
fusc(2) = fusc(1)
fusc(3) = fusc(1) + fusc(2)
fusc(71) = 11 * fusc(1) + 3 * fusc(2)
fusc(2) = fusc(1)
fusc(71) = 14 * fusc(1) = 14
We realize that we can avoid recursion completely in this case as we can always express fusc(n) in the form a * fusc(m) + b * fusc(m+1) while reducing the value of m to 0. From the example above, you may find the following pattern:
if m is odd:
a * fusc(m) + b * fusc(m+1) = a * fusc((m-1)/2) + (b+a) * fusc((m+1)/2)
if m is even:
a * fusc(m) + b * fusc(m+1) = (a+b) * fusc(m/2) + b * fusc((m/2)+1)
Therefore, you may use a simple loop function to solve the problem in O(lg(n)) time
def fusc(n):
if n == 0: return 0
a = 1
b = 0
while n > 0:
if n%2:
b = b + a
n = (n-1)/2
else:
a = a + b
n = n/2
return b
lru_cache works wonders in your case. make sure maxsize is a power of 2. may need to fiddle a bit with that size for your application. cache_info() will help with that.
also use // instead of / for integer division.
from functools import lru_cache
#lru_cache(maxsize=512, typed=False)
def fusc(n):
if n <= 1:
return n
while n > 2 and n % 2 == 0:
n //= 2
return fusc((n - 1) // 2) + fusc((n + 1) // 2)
print(fusc(1000000000078093254329870980000043298))
print(fusc.cache_info())
and yes, this is just meomization as proposed by Filip Malczak.
you might gain an additional tiny speedup using bit-operations in the while loop:
while not n & 1: # as long as the lowest bit is not 1
n >>= 1 # shift n right by one
UPDATE:
here is a simple way of doing meomzation 'by hand':
def fusc(n, _mem={}): # _mem will be the cache of the values
# that have been calculated before
if n in _mem: # if we know that one: just return the value
return _mem[n]
if n <= 1:
return n
while not n & 1:
n >>= 1
if n == 1:
return 1
ret = fusc((n - 1) // 2) + fusc((n + 1) // 2)
_mem[n] = ret # store the value for next time
return ret
UPDATE
after reading a short article by dijkstra himself a minor update.
the article states, that f(n) = f(m) if the fist and last bit of m are the same as those of n and the bits in between are inverted. the idea is to get n as small as possible.
that is what the bitmask (1<<n.bit_length()-1)-2 is for (first and last bits are 0; those in the middle 1; xoring n with that gives m as described above).
i was only able to do small benchmarks; i'm interested if this is any help at all for the magitude of your input... this will reduce the memory for the cache and hopefully bring some speedup.
def fusc_ed(n, _mem={}):
if n <= 1:
return n
while not n & 1:
n >>= 1
if n == 1:
return 1
# https://www.cs.utexas.edu/users/EWD/transcriptions/EWD05xx/EWD578.html
# bit invert the middle bits and check if this is smaller than n
m = n ^ (1<<n.bit_length()-1)-2
n = m if m < n else n
if n in _mem:
return _mem[n]
ret = fusc(n >> 1) + fusc((n >> 1) + 1)
_mem[n] = ret
return ret
i had to increase the recursion limit:
import sys
sys.setrecursionlimit(10000) # default limit was 1000
benchmarking gave strange results; using the code below and making sure that i always started a fresh interperter (having an empty _mem) i sometimes got significantly better runtimes; on other occasions the new code was slower...
benchmarking code:
print(n.bit_length())
ti = timeit('fusc(n)', setup='from __main__ import fusc, n', number=1)
print(ti)
ti = timeit('fusc_ed(n)', setup='from __main__ import fusc_ed, n', number=1)
print(ti)
and these are three random results i got:
6959
24.117448464001427
0.013900151001507766
6989
23.92404893300045
0.013844672999766772
7038
24.33894686200074
24.685758719999285
that is where i stopped...

Python function to solve binomial function

I need a function that can solve the following: for a binomial function nCr=k, given r and k find n. in mathematics nCr=n!/r!(n-r)! I tried following but it doesn't solve it. for example 8C6=28, for my function the inputs are 6 and 28 and i want to find 8. This may not have exact integer number so I want to find an x>=n.
"""
I am approaching it this way, i.e. find the solution of a polynomial function iteratively, hope there is a better way"""
"""I am approaching it this way, i.e. find the solution of a polynomial function iteratively, hope there is a better way"""
def find_n(r,k):
#solve_for_n_in(n*(n-1)...(n-r)=math.factorial(r)*k
#in the above example solve_for_n(n*(n-1)(n-2)(n-3)(n-4)(n-5)=720*28)
sum=math.factorial(r)*k
n=r
p=1
while p<sum:
p=1
for i in range(0,r+2):
p*=(n-i+1)
n+=1
return n
Thanks.
I spot a mistake in your code.
sum=n
You're setting sum to n
then,
while sum<factorial(r)*k:
sum*=n
You're multiplying sum by n again. so now sum = n**2.
this would be better:
while sum<factorial(r)*k:
n+=1
sum*=n
This is just an idea of how this problem could be approached, while maintaining a high degree of readability.
nCr = n! / {{r!}{n-r}!} = n(n-1)...(n-r+1) / {r!}
The right hand side is some value k.
Start with n = 2*(r+1).
nCr < RHS => n is too small => increase n
nCr > RHS => n is too big => decrease n
nCr == RHS => found n
...
...
Keep doing this till you find n or something goes wrong.
import math
def find_n(r,k):
if k==1:
return r # RHS is 1 when n and r are the same
RHS = math.factorial(r) * k
possible_n = 2 * r;
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
while True:
# current n is too small
if ( possible_numerator // possible_denom ) < RHS:
# try possible_n + 1
possible_n = possible_n + 1
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
elif ( possible_numerator // possible_denom ) > RHS:
# try possible_n - 1
possible_n = possible_n - 1
possible_numerator = math.factorial(possible_n)
possible_denom = math.factorial(possible_n - r)
elif ( possible_n == r):
print ("***n smaller than r***");
sys.exit(0);
elif ( possible_numerator // possible_denom ) == RHS:
return possible_n
print( find_n(6, 28) ) # should print 8
print( find_n(6, 462) ) # should print 11
print( find_n(6, 3003) ) # should print 14
print( find_n(5, 3003) ) # should print 15
I used a function that calculates the binomial coefficient to implement the feature nCr
def binomial(n,k):
return 1 if k==0 else (0 if n==0 else binomial(n-1, k) + binomial(n-1, k-1))
def nCr(r,c):
n=0
b=binomial(n,r)
while b<c:
n=n+1
b=binomial(n,r)
if b==c:
return n
return None
nCr(6,28)
8

Round integer in python without using round()

I know that I can round to the closest multiple of 10 in python by using round(<int>, -1) Is there a way to do this without using this built in function?
Edit:
Thanks for the feedback!
The answer using divmod() was interesting because I had never used divmod before. Just in case anyone wants to know on CodingBat the solution used modulo as was suggested in the comments. Here it is in case anyone is interested.
def round10(num):
mod = num % 10
num -= mod
if mod >= 5: num += 10
return num
divide by 10, int, multiply by 10.
Actually, you can do it without any builtins using the // operator:
>>> def round(x):
... return (x//10)*10
...
>>> round(15.)
10.0
>>> round(25.)
20.0
Of course, this always rounds down. If you want to round up for values with a remainder greater than 5, you could use divmod:
def round(x):
n, remainder = divmod(x, 10)
if remainder >= 5:
n += 1
return n * 10
This rounds to the closest, not always up or always down:
def xround(n):
return (n + 5) // 10 * 10
Round down to the closest multiple of 10:
int(n / 10) * 10
Round up to the closest multiple of 10:
int((n + 10) / 10) * 10
Round to the closest multiple of ten:
(int(n / 10) + bool(n % 10 >= 5)) * 10
I have a function that rounds n to the nearest multiple of d:
def cm(n,d,o="+"):
p = d - (n % d)
m = n % d
nm = n - m
np = n + p
if p > m:
return nm
elif m > p:
return np
else:
if o == "+":
return np
else:
return nm
How to use:
use cm(number, near multiple wanted, preferred direction in special cases)
Examples:
cm(8,10) = 10
cm(6,4,"-") = 4 #special case (n % d == d - n % d)
cm(6,4,"+") = 8 #special case
cm(6,4) = 8

Categories

Resources