I'm trying to implement a primality check function with a deterministic Miller-Rabin algorithm but the results are not always correct: when checking first 1,000,000 numbers it only founds 78,495 instead of 78,498.
This is obtained using [2, 7, 61] as a base which, according to wikipedia, should always be correct for values up to 4,759,123,141.
The interesting thing is that the 3 missing primes are exactly the ones componing the base (2, 7 and 61).
Why is this happening? The code I'm using is the following:
T modular_power(T base, T exponent, T modulo) {
base %= modulo;
T result = 1;
while (exponent > 0) {
if (exponent % 2 == 1)
result = (result * base) % modulo;
base = (base * base) % modulo;
exponent /= 2;
}
return result;
}
bool miller_rabin(const T& n, const vector<T>& witnesses) {
unsigned int s = 0;
T d = n - 1;
while (d % 2 == 0) {
s++;
d /= 2;
}
for (const auto& a : witnesses) {
if (modular_power<T>(a, d, n) == 1)
continue;
bool composite = true;
for (unsigned int r = 0; r < s; r++) {
if (modular_power<T>(a, (T) pow(2, r) * d, n) == n - 1) {
composite = false;
break;
}
}
if (composite)
return false;
}
return true;
}
bool is_prime(const T& n) {
if (n < 4759123141)
return miller_rabin(n, {2, 7, 61});
return false; // will use different base
}
Miller-Rabin indeed does not work when the base and the input are the same. What happens in that case is that ad mod n is zero (because a mod n is zero, so this is really raising zero to some irrelevant power), and the rest of the algorithm is unable to "escape" from zero and concludes that you're dealing with a composite.
As a special case of that, Miller-Rabin never works with an input of 2, because there is no base that can be selected. 2 itself is useless, so is 1, that leaves nothing.
Related
I have a class, call it 'BigNumber', which has a vector v field.
Each element should be one digit.
I want to implement a method to multiply this vector by an integer, but also keep elements one digit.
E.g: <7,6> * 50 = <3,8,0,0>
The vector represents a number, stored in this way. In my example, <7,6> is equal to 76, and <3,8,0,0> is 3800.
I tried the following, but this isn't good (however it works), and not the actual solution for the problem.
//int num, BigNumber bn
if (num > 0)
{
int value = 0, curr = 1;
for (int i = bn.getBigNumber().size() - 1; i >= 0; i--)
{
value += bn.getBigNumber().at(i) * num * curr;
curr *= 10;
}
bn.setBigNumber(value); //this shouldn't be here
return bn;
}
The expected algortithm is multiply the vector itself, not with a variable what I convert to this BigNumber.
The way I set Integer to BigNumber:
void BigNumber::setBigNumber(int num)
{
if (num > 0)
{
bigNum.clear();
while (num != 0)
{
bigNum.push_back(num % 10);
num = (num - (num % 10)) / 10;
}
std::reverse(bigNum.begin(), bigNum.end());
}
else
{
throw TOOSMALL;
}
};
The method I want to implement:
//class BigNumber{private: vector<int> bigNum; ... }
void BigNumber::multiplyBigNumber(BigNumber bn, int num)
{
if (num > 0)
{
//bn.bigNum * num
}
else
{
throw TOOSMALL;
}
}
As this is for a school project, I don't want to just write the code for you. So here's a hint.
Let's say you give me the number 1234 --- and I choose to store each digit in a vector in reverse. So now I've got bignum = [4, 3, 2, 1].
Now you ask me to multiply that by 5. So I create a new, empty vector result=[ ]. I look at the first item in bignum. It's a 4.
4 * 5 is 20, or (as you do at school) it is 0 carry 2. So I push the 0 into result, giving result = [0] and carry = 2.
Questions for you:
If you were doing this by hand (on paper), what would you do next?
Why did I decide to store the digits in reverse order?
Why did I decide to use a new vector (result), rather than modifying bignum?
and only after you have a worked out how to multiply a bignum by an int:
How would you multiply two bignums together?
The solutin for the problem is the follow code. I don't know if I can make this algorithm faster, but it works, so I'm happy with it.
BigNumber BigNumber::multiplyBigNumber(BigNumber bn, int num){
if (num > 0)
{
std::vector<int> result;
std::vector<int> rev = bn.getBigNumber();
std::reverse(rev.begin(),rev.end());
int carry = 0;
for(int i = 0; i<rev.size(); i++){
result.push_back((rev[i] * num + carry) % 10);
carry = (rev[i] * num + carry) / 10;
if(i == rev.size()-1 && carry / 10 == 0 && carry % 10 != 0 ) {
result.push_back(carry);
carry = carry / 10;
}
}
while((carry / 10) != 0){
result.push_back(carry % 10);
carry /= 10;
if(carry / 10 == 0) result.push_back(carry);
}
std::reverse(result.begin(),result.end());
bn.setBigNumber(result);
return bn;
}else{
throw TOOSMALL;
}
}
So for the following code I am trying to reduce the amount of time the function call itself so that it is more efficient. The purpose of the code is to perform exponentiation using recursion.
int expo(const int m, const unsigned int n)
{
funcCallCounter++; //counts how many times the function is called
if (n == 0)//base case
{
return 1;
}
else if (n % 2 == 0)// for even numbers
return expo(m*m, n / 2);
else
return m * expo(m, n - 1);//for odd numbers
}
Well this is my favourite approach for the recursive expo which will always give less calls than your approach
int expo(int a, int n) {
funcCallCounter++;
if (n == 0) {
return 1;
}
int r = expo(a, n / 2);
if (n % 2 == 0) {
//Even n
return r * r;
}
else {
// Odd n
return a *r*r;
}
}
You could use shifts to make your execution faster.
n % 2 can be replaced with n & 0x01
n / 2^k can be replaced with n >> k
A division is about 20 cycles while a shift is only 1-2 cycles.
However, maybe the compiler see taht by itself and make this optimisation already.
Best
If I want to find the total number of odd integers between a leftrange and a rightrange, do you think this works ?
example leftrange = 3, rightrange = 8.
int FindOdd(int left, int right)
{
bool lefteven = (left % 2) ? false: true;
bool righteven = (right % 2) ? false: true;
int length = (right-left) + 1;
if (lefteven != righteven) //even length
{
return (length/2);
}
else //odd length
{
if (!lefteven)
return ((length/2) + 1);
else
return (length/2);
}
}
It's a clumsy way to do it. A better way is to use integer division:
unsigned FindOdd(unsigned a, unsigned b)
{
return b / 2 - a / 2;
}
This will not include the final number if b is odd. I've cheekily changed the types to unsigned for the sake of elegance.
I have successfully coded such a program to complete this task, however my friend and I are currently having a debate over one of the values.
Here is HIS loop function:
for (int iii = 2; iii < (num / 2 + 1); iii++)
{
if (num%iii == 0)
{
return false;
}
}
return true;
My question to him is, "Why do you need "2+1"?" Can't he just use his declared variable "num"?
You only need to check up to sqrt(num), which is less than or equal num/2 for num >= 4. This is because if a number n > sqrt(num) divides num, then num/n < sqrt(num) divides num.
Proof of that claim:
The square root of a positive number n is defined as the unique positive real number x for which x * x == n holds. Now consider you have a divisor d of n such that d > n. Then there is (because d is a divisor) a natural number d2 such that d * d2 == n. It is obvious that d2 := n / d is such a number. From x * x == n, d * d2 == n and d > x one can conclude d2 < x. That means that if a number greater than x divides n, there also is a number less than x that also divides day. So in conclusion, if no number less or equal x divides n, n is prime.
That means the function is correct for all values greater or equal 2. For num >= 4 this follows immediately from the above. For num <= 1 your function will alway return true because the loop never executes. For 2 <= num <=3 the loop returns true correctly because again, the loop is never entered. (Technically, you need the +1 to proof 5 is prime because 5/2=2 < sqrt(5) because of integer division).
Some improvement:
You could test with 2, and avoid all the other even numbers.
You only need to test until sqrt(number), already explained in other answer.
Code:
#include <cmath>
bool is_prime(unsigned long number) {
if (number % 2 == 0 && number != 2)
return false;
unsigned long sqrt_number = static_cast<unsigned long>(std::sqrt(number));
for (unsigned long i = 3; i <= sqrt_number; i += 2) {
if (number % i == 0)
return false;
}
return true;
}
Your code is implementing a "prime number" test. A number is prime if it is not divisible by any whole number other than itself and 1.
This problem space has some well known parameters/factors.
a) The maximum value that any given number, N, can be divided by to produce an integer value is N/2.
b) If N is divisible by an even number, it will also be divisible by 2, i.e. it must be even.
is_prime(N) {
if is_even(N) {
// if N is 2, it's prime, otherwise
// any even number is divisible by
// 2 and thus not prime.
return (N == 2)
}
md = max_divisor(N)
// we've eliminated even numbers, so we need only
// test odd numbers.
// all numbers are divisible by 1, so start at 3.
for (divisor = 3; divisor <= md; divisor += 2) {
// determine whether divisor divides into N
// without remainder indicating non-prime N
remainder = (N % divisor)
if (remainder != 0)
return false
}
return true
}
The max divisor is a number that, when divided into N, will produce 2.
max_divisor * 2 = N ->
max_divisor = N / 2
So simply:
max_divisor(N) return N / 2
What about checking for even numbers? We can do this one of two ways. We can modulo 2, but many people trying to optimize there code will remember their binary logical and realize they just have to test if the lowest bit (bit 1) is set or not.
0001 = 1 (odd)
0010 = 2 (even)
0011 = 3 (odd)
0100 = 4 (even)
0101 = 5 (odd)
0110 = 6 (even)
0111 = 7 (odd)
very simple:
is_even(N) (N % 2) == 0
or
is_even(N) (N & 1) == 0
And converting to C:
static inline bool isEven(unsigned int number) {
return (number & 1) == 0;
}
static inline unsigned int maxDivisor(unsigned int number) {
return (number / 2);
}
unsigned int isPrime(unsigned int number) {
if (isEven(number)) {
// if N is 2, it's prime, otherwise
// any even number is divisible by
// 2 and thus not prime.
// fluffy expanded version
return (number == 2) ? true : false;
// compact version
// return (number == 2);
}
const unsigned int md = maxDivisor(number);
// we've eliminated even numbers, so we need only
// test odd numbers.
// all numbers are divisible by 1, so start at 3.
for (unsigned int divisor = 3; divisor <= md; divisor += 2) {
// determine whether divisor divides into number
// without remainder indicating non-prime number
const unsigned int remainder = (number % divisor);
if (remainder != 0)
return false;
// compact version:
//if (number % divisor)
// return false;
}
return true;
}
Your friend's "(N / 2) + 1" is because he is using a less-than rather than a <=, you could remove the "+1" in his code by writing the following:
for (int iii = 2; iii <= (num / 2); iii++)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
For the problem 10139 - Factovisors on UVa Online Judge, 2 numbers n and m are given, and we need to check whether m divides n!.
I use the algorithm:
Generate primes till const number
Take m and get its primes factor
For each prime in m's factors, calculate getpower function for n and compare them
I test different cases it give me also Wrong Answer, any suggestion?
Here's my code:
bool Factovisor (int n, int m) {
/* Special Cases */
if(n==0 && m!=1 )
return false;
else if(n==0&&m==1)
return true;
else if(m==0)
return false;
else if(m==n||m==1)
return true;
else if (n >= m)
return true;
else {
vector <factores> factores_in_m;
int index = 0;
int k=m;
/* first I generate all primes in primes vector */
for (int i = 0; i < primes.size(); i++) {
if (primes[i] > k) {
break;
} else {
/* factores is struct contain the prime and count*/
factores f = {primes[i], 0};
while (k % primes[i] == 0) {
f.count += 1;
k = k / primes[i];
}
if (f.count) {
factores_in_m.push_back(f);
}
}
}
if (k > 1) {
if (n < k) {
return false;
} else {
factores f;
f.prime= k;
f.count =1;
factores_in_m.push_back(f);
}
}
for (int i = 0; i < factores_in_m.size(); i++) {
if (factores_in_m[i].count - get_powers(n, factores_in_m[i].prime) > 0) {
return false;
}
}
return true;
}
}
int get_powers (int n, int p) {
int result = 0, power = p;
while (power <= n) {
result += n / power;
power =power* p;
}
return result;
}
bool isPrime (int n) {
for (int i = 2; i < n; i++) {
if (n % i == 0) {
return false;
}
}
return true;
}
void get_prime () {
for (int i = 2; i < maxn0; i++) {
if (isPrime(i)) {
primes.push_back(i);
}
}
}
Maybe your prime generation is faulty, but certainly your get_powers implementation is susceptible to int overflow.
int get_powers (int n, int p) {
int result = 0, power = p;
while (power <= n) {
result += n / power;
power =power* p;
}
return result;
}
If int is, as it usually is, a 32-bit wide type, for primes larger than 46341 the computation power = power * p; overflows the first time it is done. That can lead to wrong results, for example
get_powers(10000000, 131071)
returns 52 if the overflow behaviour is wraparound modulo 232, but the correct result would be 76. Now, since m is smaller than 231, this particular one wouldn't hurt, since m cannot be divisible by 131071². But under the wraparound behaviour,
get_powers(1000000, 699733) = -2192
is negative, so for n = 1000000 and m = 2*699733 for example, you would wrongly conclude that n! isn't divisible by m.
To avoid the possible overflow, only divide by p,
int get_powers(int n, int p) {
int result = 0;
n /= p;
do {
result += n;
n /= p;
}while(n > 0);
return result;
}
From the comments:
I edited to add my functions to get primes till constant number "maxn0" – userG 2 hours ago
What value have you chosen for maxn0? – Daniel Fischer 2 hours ago
maxn0 = 10000
That value is too small.
With the primes to 10000, you are only guaranteed to correctly factorise numbers not exceeding 108 (well, since the next prime is 10007, numbers smaller than 10007² = 100140049), but the limit is given as 231, which is much larger.
Whenever a number m is given with two (not necessarily distinct) prime factors larger than 10000, you will not correctly factorise that, and that will usually lead to a wrong answer.
You need all primes ≤ √(231-1), that is all primes < 46340 to obtain the correct factorisation of all admissible m.
EDIT: wrong answer due to a misanderstanding of the question.
9 divides 7! but your algorithm will answer false because get_powers(7, 3) == 0 and 3 is a factor of 9.
It is not your implementation that is wrong but your algorithm.