I'm trying to write miller-rabin test. I found few codes such as:
https://www.sanfoundry.com/cpp-program-implement-miller-rabin-primality-test/
https://www.geeksforgeeks.org/primality-test-set-3-miller-rabin/
Of course all this codes works for 252097800623 ( which is prime number ), but this is becaouse they are parsing it to int. When I changed all ints to long long in this codes they are now returning NO. I also wrote my own code based on another article and it worked when I was testing it with small numbers like 11, 101, 17 and even 1000000007, but chrashed on greater numbers like 252097800623. I want to write program that works for all integers from 1 to 10^18
EDIT
here is modified code form 1st link:
/*
* C++ Program to Implement Milong longer Rabin Primality Test
*/
#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
/*
* calculates (a * b) % c taking long longo account that a * b might overflow
*/
long long mulmod(long long a, long long b, long long mod)
{
long long x = 0,y = a % mod;
while (b > 0)
{
if (b % 2 == 1)
{
x = (x + y) % mod;
}
y = (y * 2) % mod;
b /= 2;
}
return x % mod;
}
/*
* modular exponentiation
*/
long long modulo(long long base, long long exponent, long long mod)
{
long long x = 1;
long long y = base;
while (exponent > 0)
{
if (exponent % 2 == 1)
x = (x * y) % mod;
y = (y * y) % mod;
exponent = exponent / 2;
}
return x % mod;
}
/*
* Milong longer-Rabin primality test, iteration signifies the accuracy
*/
bool Miller(long long p,long long iteration)
{
if (p < 2)
{
return false;
}
if (p != 2 && p % 2==0)
{
return false;
}
long long s = p - 1;
while (s % 2 == 0)
{
s /= 2;
}
for (long long i = 0; i < iteration; i++)
{
long long a = rand() % (p - 1) + 1, temp = s;
long long mod = modulo(a, temp, p);
while (temp != p - 1 && mod != 1 && mod != p - 1)
{
mod = mulmod(mod, mod, p);
temp *= 2;
}
if (mod != p - 1 && temp % 2 == 0)
{
return false;
}
}
return true;
}
//Main
int main()
{
long long iteration = 5;
long long num;
cout<<"Enter long longeger to test primality: ";
cin>>num;
if (Miller(num, iteration))
cout<<num<<" is prime"<<endl;
else
cout<<num<<" is not prime"<<endl;
return 0;
}
The code in the first link, which you replicated in your question, replacing the (bad) macro ll with long long (although this produces exactly the same preprocessed code) and all int with long long, is already broken for large values, see compiler explorer here. I forced the compiler to evaluate the Miller function for 252097800623 at compile time, replacing the call to rand() with one random number 123456.
As you can see the compiler is telling me that it cannot do so, because there are integer overflows in the program. In particular:
<source>:133:17: error: static_assert expression is not an integral constant expression
static_assert(Miller(num, iteration));
^~~~~~~~~~~~~~~~~~~~~~
<source>:62:12: note: value 232307310937188460801 is outside the range of representable values of type 'long long'
y = (y * y) % mod;
^
<source>:104:14: note: in call to 'modulo(123457, 63024450155, 252097800623)'
ll mod = modulo(a, temp, p);
^
<source>:133:17: note: in call to 'Miller(252097800623, 5)'
static_assert(Miller(num, iteration));
As you can see long long is simply too small to handle inputs that large to this algorithm.
Related
This problem's answer turns out to be calculating large binomial coefficients modulo prime number using Lucas' theorem. Here's the solution to that problem using this technique: here.
Now my questions are:
Seems like my code expires if the data increases due to overflow of variables. Any ways to handle this?
Are there any ways to do this without using this theorem?
EDIT: note that as this is an OI or ACM problem, external libs other than original ones are not permitted.
Code below:
#include <iostream>
#include <string.h>
#include <stdio.h>
using namespace std;
#define N 100010
long long mod_pow(int a,int n,int p)
{
long long ret=1;
long long A=a;
while(n)
{
if (n & 1)
ret=(ret*A)%p;
A=(A*A)%p;
n>>=1;
}
return ret;
}
long long factorial[N];
void init(long long p)
{
factorial[0] = 1;
for(int i = 1;i <= p;i++)
factorial[i] = factorial[i-1]*i%p;
//for(int i = 0;i < p;i++)
//ni[i] = mod_pow(factorial[i],p-2,p);
}
long long Lucas(long long a,long long k,long long p)
{
long long re = 1;
while(a && k)
{
long long aa = a%p;long long bb = k%p;
if(aa < bb) return 0;
re = re*factorial[aa]*mod_pow(factorial[bb]*factorial[aa-bb]%p,p-2,p)%p;
a /= p;
k /= p;
}
return re;
}
int main()
{
int t;
cin >> t;
while(t--)
{
long long n,m,p;
cin >> n >> m >> p;
init(p);
cout << Lucas(n+m,m,p) << "\n";
}
return 0;
}
This solution assumes that p2 fits into an unsigned long long. Since an unsigned long long has at least 64 bits as per standard, this works at least for p up to 4 billion, much more than the question specifies.
typedef unsigned long long num;
/* x such that a*x = 1 mod p */
num modinv(num a, num p)
{
/* implement this one on your own */
/* you can use the extended Euclidean algorithm */
}
/* n chose m mod p */
/* computed with the theorem of Lucas */
num modbinom(num n, num m, num p)
{
num i, result, divisor, n_, m_;
if (m == 0)
return 1;
/* check for the likely case that the result is zero */
if (n < m)
return 0;
for (n_ = n, m_ = m; m_ > 0; n_ /= p, m_ /= p)
if (n_ % p < m_ % p)
return 0;
for (result = 1; n >= p || m >= p; n /= p, m /= p) {
result *= modbinom(n % p, m % p, p);
result %= p;
}
/* avoid unnecessary computations */
if (m > n - m)
m = n - m;
divisor = 1;
for (i = 0; i < m; i++) {
result *= n - i;
result %= p;
divisor *= i + 1;
divisor %= p;
}
result *= modinv(divisor, p);
result %= p;
return result;
}
An infinite precision integer seems like the way to go.
If you are in C++,
the PicklingTools library has an "infinite precision" integer (similar to
Python's LONG type). Someone else suggested Python, that's a reasonable
answer if you know Python. if you want to do it in C++, you can
use the int_n type:
#include "ocval.h"
int_n n="012345678910227836478627843";
n = n + 1; // Can combine with other plain ints as well
Take a look at the documentation at:
http://www.picklingtools.com/html/usersguide.html#c-int-n-and-the-python-arbitrary-size-ints-long
and
http://www.picklingtools.com/html/faq.html#c-and-otab-tup-int-un-int-n-new-in-picklingtools-1-2-0
The download for the C++ PicklingTools is here.
You want a bignum (a.k.a. arbitrary precision arithmetic) library.
First, don't write your own bignum (or bigint) library, because efficient algorithms (more efficient than the naive ones you learned at school) are difficult to design and implement.
Then, I would recommend GMPlib. It is free software, well documented, often used, quite efficient, and well designed (with perhaps some imperfections, in particular the inability to plugin your own memory allocator in replacement of the system malloc; but you probably don't care, unless you want to catch the rare out-of-memory condition ...). It has an easy C++ interface. It is packaged in most Linux distributions.
If it is a homework assignment, perhaps your teacher is expecting you to think more on the math, and find, with some proof, a way of solving the problem without any bignums.
Lets suppose that we need to compute a value of (a / b) mod p where p is a prime number. Since p is prime then every number b has an inverse mod p. So (a / b) mod p = (a mod p) * (b mod p)^-1. We can use euclidean algorithm to compute the inverse.
To get (n over k) we need to compute n! mod p, (k!)^-1, ((n - k)!)^-1. Total time complexity is O(n).
UPDATE: Here is the code in c++. I didn't test it extensively though.
int64_t fastPow(int64_t a, int64_t exp, int64_t mod)
{
int64_t res = 1;
while (exp)
{
if (exp % 2 == 1)
{
res *= a;
res %= mod;
}
a *= a;
a %= mod;
exp >>= 1;
}
return res;
}
// This inverse works only for primes p, it uses Fermat's little theorem
int64_t inverse(int64_t a, int64_t p)
{
assert(p >= 2);
return fastPow(a, p - 2, p);
}
int64_t binomial(int64_t n, int64_t k, int64_t p)
{
std::vector<int64_t> fact(n + 1);
fact[0] = 1;
for (auto i = 1; i <= n; ++i)
fact[i] = (fact[i - 1] * i) % p;
return ((((fact[n] * inverse(fact[k], p)) % p) * inverse(fact[n - k], p)) % p);
}
I have made a recursive function in c++ which deals with very large integers.
long long int findfirst(int level)
{
if(level==1)
return 1;
else if(level%2==0)
return (2*findfirst(--level));
else
return (2*findfirst(--level)-1);
}
when the input variable(level) is high,it reaches the limit of long long int and gives me wrong output.
i want to print (output%mod) where mod is 10^9+7(^ is power) .
int main()
{
long long int first = findfirst(143)%1000000007;
cout << first;
}
It prints -194114669 .
Normally online judges problem don't require the use of large integers (normally meaning almost always), if your solution need large integers probably is not the best solution to solve the problem.
Some notes about modular arithmetic
if a1 = b1 mod n and a2 = b2 mod n then:
a1 + a2 = b1 + b2 mod n
a1 - a2 = b1 - b2 mod n
a1 * a2 = b1 * b2 mod n
That mean that modular arithmetic is transitive (a + b * c) mod n could be calculated as (((b mod n) * (c mod n)) mod n + (a mod n)) mod n, I know there a lot of parenthesis and sub-expression but that is to avoid integer overflow as much as we can.
As long as I understand your program you don't need recursion at all:
#include <iostream>
using namespace std;
const long long int mod_value = 1000000007;
long long int findfirst(int level) {
long long int res = 1;
for (int lev = 1; lev <= level; lev++) {
if (lev % 2 == 0)
res = (2*res) % mod_value;
else
res = (2*res - 1) % mod_value;
}
return res;
}
int main() {
for (int i = 1; i < 143; i++) {
cout << findfirst(i) << endl;
}
return 0;
}
If you need to do recursion modify you solution to:
long long int findfirst(int level) {
if (level == 1)
return 1;
else if (level % 2 == 0)
return (2 * findfirst(--level)) % mod_value;
else
return (2 * findfirst(--level) - 1) % mod_value;
}
Where mod_value is the same as before:
Please make a good study of modular arithmetic and apply in the following online challenge (the reward of discovery the solution yourself is to high to let it go). Most of the online challenge has a mathematical background.
If the problem is (as you say) it overflows long long int, then use an arbitrary precision Integer library. Examples are here.
I want to find (n choose r) for large integers, and I also have to find out the mod of that number.
long long int choose(int a,int b)
{
if (b > a)
return (-1);
if(b==0 || a==1 || b==a)
return(1);
else
{
long long int r = ((choose(a-1,b))%10000007+(choose(a-1,b- 1))%10000007)%10000007;
return r;
}
}
I am using this piece of code, but I am getting TLE. If there is some other method to do that please tell me.
I don't have the reputation to comment yet, but I wanted to point out that the answer by rock321987 works pretty well:
It is fast and correct up to and including C(62, 31)
but cannot handle all inputs that have an output that fits in a uint64_t. As proof, try:
C(67, 33) = 14,226,520,737,620,288,370 (verify correctness and size)
Unfortunately, the other implementation spits out 8,829,174,638,479,413 which is incorrect. There are other ways to calculate nCr which won't break like this, however the real problem here is that there is no attempt to take advantage of the modulus.
Notice that p = 10000007 is prime, which allows us to leverage the fact that all integers have an inverse mod p, and that inverse is unique. Furthermore, we can find that inverse quite quickly. Another question has an answer on how to do that here, which I've replicated below.
This is handy since:
x/y mod p == x*(y inverse) mod p; and
xy mod p == (x mod p)(y mod p)
Modifying the other code a bit, and generalizing the problem we have the following:
#include <iostream>
#include <assert.h>
// p MUST be prime and less than 2^63
uint64_t inverseModp(uint64_t a, uint64_t p) {
assert(p < (1ull << 63));
assert(a < p);
assert(a != 0);
uint64_t ex = p-2, result = 1;
while (ex > 0) {
if (ex % 2 == 1) {
result = (result*a) % p;
}
a = (a*a) % p;
ex /= 2;
}
return result;
}
// p MUST be prime
uint32_t nCrModp(uint32_t n, uint32_t r, uint32_t p)
{
assert(r <= n);
if (r > n-r) r = n-r;
if (r == 0) return 1;
if(n/p - (n-r)/p > r/p) return 0;
uint64_t result = 1; //intermediary results may overflow 32 bits
for (uint32_t i = n, x = 1; i > r; --i, ++x) {
if( i % p != 0) {
result *= i % p;
result %= p;
}
if( x % p != 0) {
result *= inverseModp(x % p, p);
result %= p;
}
}
return result;
}
int main() {
uint32_t smallPrime = 17;
uint32_t medNum = 3001;
uint32_t halfMedNum = medNum >> 1;
std::cout << nCrModp(medNum, halfMedNum, smallPrime) << std::endl;
uint32_t bigPrime = 4294967291ul; // 2^32-5 is largest prime < 2^32
uint32_t bigNum = 1ul << 24;
uint32_t halfBigNum = bigNum >> 1;
std::cout << nCrModp(bigNum, halfBigNum, bigPrime) << std::endl;
}
Which should produce results for any set of 32-bit inputs if you are willing to wait. To prove a point, I've included the calculation for a 24-bit n, and the maximum 32-bit prime. My modest PC took ~13 seconds to calculate this. Check the answer against wolfram alpha, but beware that it may exceed the 'standard computation time' there.
There is still room for improvement if p is much smaller than (n-r) where r <= n-r. For example, we could precalculate all the inverses mod p instead of doing it on demand several times over.
nCr = n! / (r! * (n-r)!) {! = factorial}
now choose r or n - r in such a way that any of them is minimum
#include <cstdio>
#include <cmath>
#define MOD 10000007
int main()
{
int n, r, i, x = 1;
long long int res = 1;
scanf("%d%d", &n, &r);
int mini = fmin(r, (n - r));//minimum of r,n-r
for (i = n;i > mini;i--) {
res = (res * i) / x;
x++;
}
printf("%lld\n", res % MOD);
return 0;
}
it will work for most cases as required by programming competitions if the value of n and r are not too high
Time complexity :- O(min(r, n - r))
Limitation :- for languages like C/C++ etc. there will be overflow if
n > 60 (approximately)
as no datatype can store the final value..
The expansion of nCr can always be reduced to product of integers. This is done by canceling out terms in denominator. This approach is applied in the function given below.
This function has time complexity of O(n^2 * log(n)). This will calculate nCr % m for n<=10000 under 1 sec.
#include <numeric>
#include <algorithm>
int M=1e7+7;
int ncr(int n, int r)
{
r=min(r,n-r);
int A[r],i,j,B[r];
iota(A,A+r,n-r+1); //initializing A starting from n-r+1 to n
iota(B,B+r,1); //initializing B starting from 1 to r
int g;
for(i=0;i<r;i++)
for(j=0;j<r;j++)
{
if(B[i]==1)
break;
g=__gcd(B[i], A[j] );
A[j]/=g;
B[i]/=g;
}
long long ans=1;
for(i=0;i<r;i++)
ans=(ans*A[i])%M;
return ans;
}
I was doing this problem called arithmetic progression on Hackerrank.
https://www.hackerrank.com/challenges/arithmetic-progressions
My solution passed all first six tests. I have tried every possible way of optimizing my code, including caching, more efficient operation. I still could not pass the test. The two places I think I failed is factorial function and pow function.
Basically, I used unordered_map to store all of the previous results. If the argument is one of the key, I will just returned the result right away.
Here is my code:
#include <cstdio>
#include <vector>
#include <iostream>
#include <algorithm>
#include <unordered_map>
#include <utility>
#include <ctime>
#include <sys/time.h>
using namespace std;
#define mod(m) (m > 1000003) ? m % 1000003 : m
//used for hashing the pair
namespace std {
template<typename a, typename b>
struct hash< pair<a, b> > {
private:
const hash<a> ah;
const hash<b> bh;
public:
hash() : ah(), bh() {};
size_t operator()(const std::pair<a, b> &p) const {
return ah(p.first) ^ bh(p.second);
}
};
} // namespaces
//the code below is used for collecting statistics
/*
typedef unsigned long long timestamp_t;
static timestamp_t get_timestamp ()
{
struct timeval now;
gettimeofday (&now, NULL);
return now.tv_usec + (timestamp_t)now.tv_sec * 1000000;
}
*/
//note that the number could get really large, that's why I use unsigned long long for most of data type
static unsigned long long cache_D[100000];
static unsigned long long cache_d[100000];
static unsigned long long cache_p[100000];
static unordered_map<unsigned long long, unsigned long long> cache_F; //use unordered_map to store the factorial, avg insert, lookup O(1)
static unordered_map<pair<unsigned long long, unsigned long long>, unsigned long long> cache_P; //use unordered_map to store the pow
//static double pow_sec = 0;
//static double fac_sec = 0;
/**
* Use the fast pow algorithm. On top of that, I add caching (stored in unordered map) to speed up the pow
* #param x base
* #param y exponent
* #return x ^ y
*/
unsigned long long pow(unsigned long long x, unsigned long long y)
{
//timestamp_t t0 = get_timestamp();
pair<unsigned long long, unsigned long long> curr(x, y);
if(cache_P.find(curr) != cache_P.end())
{
//timestamp_t t1 = get_timestamp();
//pow_sec += (t1 - t0) / 1000000.0L;
return cache_P[curr];
}
unsigned long long result = 1;
unsigned long long mod_x = mod(x);
//unsigned long long count = 0;
while( y )
{
if ( y & 1 )
{
unsigned long long temp = result * mod_x;
result = mod(temp);
}
y >>= 1;
unsigned long long temp = mod_x * mod_x;
mod_x = mod(temp);
}
cache_P[curr] = result;
//timestamp_t t1 = get_timestamp();
//pow_sec += (t1 - t0) / 1000000.0L;
return result;
}
/**
* same idea as pow, caching whenever I can
* #param x number to be factorialized
* #return x!
*/
unsigned long long factorial(unsigned long long x)
{
//timestamp_t t0 = get_timestamp();
if (cache_F.find(x) != cache_F.end())
{
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0) / 1000000.0L;
return cache_F[x];
}
else
{
unsigned long long result = 1;
//here we go from x to 1 since we could speed up operation as soon as we have x - 1 or x - 2 or x - 3 in our caching (just x * (x - 1)! )
for(unsigned long long i = x; i >= 1; i--)
{
if(cache_F.find(i) != cache_F.end())
{
unsigned long long temp1 = result * cache_F[i];
result = mod(temp1);
cache_F[x] = result;
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0) / 1000000.0L;
return result;
}
unsigned long long mod_i = mod(i);
unsigned long long temp2 = result * mod_i;
result = mod(temp2);
}
cache_F[x] = result;
//timestamp_t t1 = get_timestamp();
//fac_sec += (t1 - t0) / 1000000.0L;
return result;
}
}
void query(int from, int to)
{
unsigned long long k = 0;
unsigned long long constant = 1;
for(int i = from - 1; i < to; i++)
{
k += cache_p[i];
unsigned long long temp = constant * cache_D[i];
constant = mod(temp);
}
unsigned long long temp = constant * factorial(k);
constant = mod(temp);
printf("%llu %llu\n", k, constant);
}
void update(int from, int to, int how_much)
{
for(int i = from - 1; i < to; i++)
{
cache_p[i] += how_much;
unsigned long long temp = cache_D[i] * pow(cache_d[i], (unsigned long long)how_much);
cache_D[i] = mod(temp);
}
}
int main() {
int num_vec, num_operations;
FILE *pFile = fopen("input.txt", "r");
fscanf(pFile, "%d", &num_vec);
for(int i = 0; i < num_vec; i++)
{
unsigned long long a, d, q;
fscanf(pFile, "%llu %llu %llu", &a, &d, &q);
cache_d[i] = d;
cache_p[i] = q;
cache_D[i] = pow(d, q);
}
fscanf(pFile, "%d", &num_operations);
for(int i = 0; i < num_operations; i++)
{
int what_operation, from, to;
fscanf(pFile, "%d %d %d", &what_operation, &from, &to);
if(what_operation == 0)
{
query(from, to);
}
else if (what_operation == 1)
{
int add_q;
fscanf(pFile, "%d", &add_q);
update(from, to, add_q);
}
}
printf("sec for pow: %f\n sec for fac: %f", pow_sec, fac_sec);
return 0;
}
It would be really helpful if anyone knows how to further optimize my code. Thanks!
Regarding Factorial.
"unsigned long long" has a range from 0 to
18,446,744,073,709,551,615
the factorial of 21 is:
51,090,942,171,709,440,000
So, this means your function can only return the correct results for factorial of 0 through 20.
It will be a lot easier to start with a pre-built cache with 21 elements (zero through 20).
unsigned long long fact_cache [21] = {
1 ,
1 ,
2 ,
6 ,
24 ,
120 ,
720 ,
5040 ,
40320 ,
362880 ,
3628800 ,
39916800 ,
479001600 ,
6227020800 ,
87178291200 ,
1307674368000 ,
20922789888000 ,
355687428096000 ,
6402373705728000 ,
121645100408832000 ,
2432902008176640000
};
Now your factorial function can just look up the right value in the array (checking bounds if you like).
edit: (Realized the OP intended 'factorial mod 1000003")
I started by reading the answers to:
Fast way to calculate n! mod m where m is prime?
Based on the second answer, with code examples in python, and more information here:
http://www.algorithmist.com/index.php/Modular_inverse
He gave this Python code, as well as a possible improvement.
def factorialMod(n, modulus):
ans=1
if n <= modulus//2:
#calculate the factorial normally (right argument of range() is exclusive)
for i in range(1,n+1):
ans = (ans * i) % modulus
else:
#Fancypants method for large n
for i in range(n+1,modulus):
ans = (ans * i) % modulus
ans = modinv(ans, modulus)
ans = -1*ans + modulus
return ans % modulus
This has some advantages, over the original method when n is larger than the modulus divided by 2, since we can reduce the number of multiplications by solving for the modular inverse.
Because we know the modulus (1000003), we can solve for the modinv by using its totient (1000002).
In pseudo-code we get something like:
long factorial_mod( long n ) {
if( n > 1000003 )
return 0; //from Thomas's comment
if( cache[n] != 0 ) //if the cache has the answer
return cache[n];
long result = 1;
if ( n <= 500001 )
{
for( long i = 1; i <= n; i++ )
{
result = (result * i) % 1000003;
cache[i] = result;
}
}
else
{
for( long i = n+1; i <= 1000003; i++)
{
result = (result * i) % 1000003;
}
result = modinv(result, 1000003);
result = -1*result + 1000003;
}
result = result % 1000003;
cache[n] = result;
return result;
}
long modinv( long a, int modulus ) {
return modPow( a, 1000002, modulus); // ( (a to the totient) mod the modulus )
}
If we didn't want to compute the totient, we could have used extended euler GCD to solve for the modular inverse. (of course the totient of primes is very easy to compute...just subtract one).
The following code is used to print an int. How can I modify it to print a long long int? Please explain.
For pc, read putchar_unlocked
inline void writeInt (int n)
{
int N = n, rev, count = 0;
rev = N;
if (N == 0) { pc('0'); pc('\n'); return ;}
while ((rev % 10) == 0) { count++; rev /= 10;}
rev = 0;
while (N != 0) { rev = (rev<<3) + (rev<<1) + N % 10; N /= 10;}
while (rev != 0) { pc(rev % 10 + '0'); rev /= 10;}
while (count--) pc('0');
pc('\n');
return ;
}
There's nothing specific about int in the code. Just replace both occurrences of "int" by "long long int", and you're done.
(I find the "optimization" of *10 via shift and add quite ridiculous with all the divisions that remain. Any decent C compiler will do that (and much more) automatically. And don't forget to profile this "fast" version against the stdlib routine, to be sure it really was worth the effort).
This code is a lit more complex than it needs to be:
inline void writeLongLong (long long n)
{
char buffer[sizeof(n) * 8 * 3 / 10 + 3]; // 3 digits per 10 bits + two extra and space for terminating zero.
int index = sizeof(buffer)-1;
int end = index;
buffer[index--] = 0;
do {
buffer[index--] = (n % 10) + '0';
n /= 10;
} while(n);
puts(&buffer[index+1]);
}
This does the same job, with about half as many divide/modulo operations and at least I can follow it better. Note that stdio/stdlib functions are probably better than this, and this function does not cope with negative numbers (neither does the one posted above).