2

Here is the problem I am trying to solve:

Define a class named PrimeNumber that stores a prime number. The default constructor should set the prime number to 1. Add another constructor that allows the caller to set the prime number. Also, add a function to get the prime number. Finally, overload the prefix and postfix ++ and -- operators so they return a PrimeNumber object that is the next largest prime number (for ++) and the next smallest prime number (for --). For example, if the object's prime number is set to 13, then invoking ++ should return a PrimeNumber object whose prime number is set to 17. Create an appropriate test program for the class.

This is not for a class, I am just trying to teach myself C++ because I need it as I will start my PhD in financial mathematics at FSU this fall. Here is my code thus far:

#include <iostream>
#include "PrimeNumber.h"
using namespace std;

int main() {
int x;
cout << "\nenter prime number: ";
cin >> x;

PrimeNumber p(x);
    PrimeNumber q(x);
p++;
    q--;
    cout << "\nprime before is " << q.GetPrime() << endl;
cout << "\nnext prime is " << p.GetPrime() << endl;

return 0;


}


class PrimeNumber {
int prime;
public:
PrimeNumber():prime(0){};
PrimeNumber(int num);
void SetPrime(int num);
int GetPrime(){return prime;};
PrimeNumber& operator++(int);
PrimeNumber& operator--(int);
static bool isPrime(int num);


};

void PrimeNumber::SetPrime(int num) {
if(isPrime(num)){
    prime = num;
}else{
    cout << num << " is not a prime Defaulting to 0.\n";
    prime = 0;
  }
 }

 PrimeNumber::PrimeNumber(int num){
  if(isPrime(num))
    prime = num;
  else {
    cout << num << " is not prime. Defaulting to 0.\n";
    prime = 0;
  }
 }


PrimeNumber& PrimeNumber::operator++(int){
//increment prime by 1 and test primality
//loop until a prime is found
do 
{
    this->prime += 1;
} 
while (! PrimeNumber::isPrime(this->prime));

}

PrimeNumber& PrimeNumber::operator--(int){
do 
{
    this->prime -= 1;
} 
while (!PrimeNumber::isPrime(this->prime));

}

bool PrimeNumber::isPrime(int num) {
if(num < 2)
    return false;

if(num == 2)
    return true;

if(num % 2 == 0)
    return false;

const int max_divisor = sqrt(num);
for(int div = 3; div < max_divisor; div += 2) // iterate odd numbers only
    if(num % div == 0)
        return false;
return true;
 }

So, my question here is that for the bool isPrime function, I first say OK the prime numbers 2 and 3 are primes and then I eliminate any numbers that are multiples of 2 or 3. What I want to do is perhaps create a while loop that would eliminate the other multiples of the number leaving the prime numbers only. Although, I am not exactly sure how to achieve this, if anyone has any suggestions, I would greatly appreciate it.

Now that is taken care of, I can't seem to get the ++ and -- operators working correctly. Sometimes it works and sometimes it doesn't.

  • 5
    No offense please. Are you really PhD student? Did you hear about Little Fermat's Theorem? And what about wikipedia? http://en.wikipedia.org/wiki/Primality_test – ibre5041 May 22 '15 at 11:18
  • BTW, I don't see the overloaded constructor! – CinCout May 22 '15 at 11:20
  • 4
    "The default constructor should set the prime number to 1." No. No, no, no, no, no. 1 is not prime. – molbdnilo May 22 '15 at 11:22
  • 2
    Why would you want the default constructor to "set the prime number to 1"? 1 is not a prime value. Anyway, look of Sieve of Eratosthenes. – Peter May 22 '15 at 11:23
  • @ibre5041 Yes, I am. Obviously I have no experience with C++, I was a business and mathematical finance major at USC for my undergrad and most of my classes were theory based hence my programming skills are still at the beginner level, make sense? –  May 22 '15 at 11:26
  • @ibre5041 Why did you ask if I was really a PhD student? –  May 22 '15 at 13:12
  • @MorganWeiss from someone who studied math I would expect familiarity with Number Theory. So I would expect question starting with: "I trying to implement deterministic/probabilistic algorithm XY for primality test as explained in article ABC..." – ibre5041 May 22 '15 at 13:17
  • @ibre5041 I understand, but yet I studied mathematical finance not pure math which did not require number theory, I found your question rather insulting. –  May 22 '15 at 13:22

2 Answers2

6

What I want to do is perhaps create a while loop that would eliminate the other multiples of the number leaving the prime numbers only. Although, I am not exactly sure how to achieve this, if anyone has any suggestions, I would greatly appreciate it.

The algorithm you want to apply is called the Sieve of Erathostenes.

Instead of doing that (it would require that you store more and more prime numbers as you increment an instance), consider the algorithm proposed by Juraj Blaho (that tends to be the simplest).

Edit: consider this algorithm instead:

bool PrimeNumber::isPrime(int num) {
    if(num < 2)
        return false;
    if(num == 2)
        return true;
    if(num % 2 == 0)
        return false;

    const int root = sqrt(num);
    for(int div = 3; div <= root; div += 2) // iterate odd numbers only
        if(num % div == 0)
            return false;
    return true;
}

This is much faster (for large numbers) than the solution proposed by Juraj Blaho.

End Edit.

If you are instead looking for partial solutions (almost prime numbers, numbers that are "probably prime") consider the Rabin-Miller probabilistic primality test (or other tests linked to, from that page).

Community
  • 1
  • 1
utnapistim
  • 24,817
  • 3
  • 41
  • 76
  • Can you provide any numbers about how much faster it is that the simpler algorithm? – Juraj Blaho May 22 '15 at 11:39
  • 1
    @JurajBlaho, when I wrote that, you were performing `num - 2` iterations, not `sqrt(num - 2)`. Now mine is still faster, because iterating in increments of two, my algorithm performs `sqrt(num - 2) / 2` operations. On top of that, you are performing an unnecessary product on each iteration (which while blazingly-fast on today's computers, it is slower than not doing that at all). That said, I cannot post any concrete numbers: I am in office and have (other) work to do :(. – utnapistim May 22 '15 at 11:43
  • If number is 9 then sqrt will be 3 then according to the algorithm , it will return true (9 is prime) for(int div = 3; div < root; div += 2) , correct me if i am wrong. – udit043 May 22 '15 at 11:45
  • @uditr043 You are correct; I have changed the code to include the root in the loop (using `<=` now). – utnapistim May 22 '15 at 11:47
  • If number is 10 then sqrt will be 3 then according to the algorithm , it will return true (10 is prime) for(int div = 3; div <= root; div += 2) , correct me if i am wrong. – udit043 May 22 '15 at 11:56
  • @uditr043, if the number is 10, it divides by 2 in the test right before entering the loop and the algorithm returns false. – utnapistim May 22 '15 at 12:02
1

To check if a number is prime, you just need to check the remainder after division of each number smaller than square root of the tested number. Additionally some extra checks need to be performed for numbers smaller or equal to 1.

bool isPrime(int x)
{
  if (x <= 1)
    return false;

  for (int i = 2; i * i <= x; ++i)
    if (x % i == 0)
      return false;

  return true;
}

If an optimized version without any floating point calculations and square roots is needed:

bool isPrime(int x)
{
  if (x <= 1)
    return false;
  if (x <= 3)
    return true;
  if (x % 2 == 0)
    return false;

  for (int i = 2; ; i += 2)
  {
    const auto result = std::div(x, i);
    if (result.rem == 0)
      return false;
    if (result.quot < i)
      return true;
  }

  return true;
}
Juraj Blaho
  • 12,713
  • 5
  • 46
  • 92
  • Why the i*i in your for loop?? And why those two if conditions in teh beginning? –  May 22 '15 at 11:23
  • @Pickle: Because there is no need to check all numbers smaller than `x`. Just those smaller than square root of `x`. – Juraj Blaho May 22 '15 at 11:24
  • 1
    But in this case you have to calculate `i * i` at every iteration. If `x` is very large this will require a lot of useless multiplications. I would rather calculate the square root *once*, before the loop, and stop there. Ok, maybe optimizations are not so important in this case, but whenever you are crunching numbers I'd consider them. – Fabio says Reinstate Monica May 22 '15 at 11:30
  • @FabioTurati: This was just to give the simplest possible algorithm. However many optimizations are possible, but calculating square root is not a cheap operation either. Can you make a benchmark to prove that it is actually faster and worth the effort? – Juraj Blaho May 22 '15 at 11:35
  • No need for benchmarks, it's common sense that calculating something once is faster than calculating it many times. –  May 22 '15 at 11:39
  • That std::div is so ugly... Why not use a / and a %? –  May 22 '15 at 12:34
  • @Pickle: Because, `div` should be more efficient. It should be one instruction on x86 instead of two even without compiler doing optimizations. I have not performed any profiling though. It is just "common sense" without any evidence. – Juraj Blaho May 22 '15 at 13:00
  • I have just checked, out of curiosity, how fast it is to calculate a square root. It is **much** faster than I thought. On modern Intel processors it only takes the same time as 4 multiplications, and on older CPUs it takes the time of 14 multiplications. See http://stackoverflow.com/questions/7724061/how-slow-how-many-cycles-is-calculating-a-square-root for reference. Not sure about AMD processors (but I expect similar numbers), and it could be very different for other architectures (like ARM), but at least on x64 I think we can say the cost of a square root is trivial. – Fabio says Reinstate Monica May 22 '15 at 13:03
  • @FabioTurati: Yes, it may be faster, I was just concerned how large the benefit would be. I would suspect the running time to be dominated by the division and condition inside the loop. But I have no numbers to confirm that. – Juraj Blaho May 22 '15 at 13:19