tags:

views:

689

answers:

10

My code is pasted below.When I run this program,it keeps on calculating.I am using the old Turbo C++ compiler.How much time should such a program take to execute?I waited about 5 minutes but there wasn't any output.

/*The sum of the primes below 10 is 2 + 3 + 5 + 7 = 17.

Find the sum of all the primes below two million.
*/
#include<stdio.h>
#include<conio.h>
#define TWO_MILLION 2*1000*1000
int IsPrime(long unsigned int num);
int main()
{
    long unsigned int i,sum=0;
    clrscr();
    for(i=2;i<TWO_MILLION;i++)
    {
        if(IsPrime(i))
        sum+=i;
    }
    gotoxy(25,25);
    printf("%ld",sum);
    getch();
    return 0;
}
int IsPrime(long unsigned int num)
{
    int flag=1;
    long unsigned int i;
    for(i=2;i<num;i++)
    {
        if(num%i==0)
        {
            flag=0;
            break;
        }
    }
    return flag;
}
+3  A: 

How much time should such a program take to execute?

That depends completely on your platform. I suspect since you're performing ~(two million)^2 operations (~four trillion) calculations, an awful long time.

There are much better ways to perform what you're doing -- for example to check prime you only need to check to the square root of the number, not all the way up to the number itself. Not to mention there is probably a dynamic programming solution which can do it much much faster than that.

Billy ONeal
The crazy thing is that four trillion modulo operations (much less, actually, because he did at least implement early exit) isn't necessarily infeasible on modern hardware. Throwing a 1 GHz GPU at the problem, which does 256 operations per cycle (conservative), you have 250 billion ops/sec, or 10-20 seconds, give or take.
Potatoswatter
@Potatoswatter: x86 certainly cannot do 256 operations/cycle. You get one operation a cycle there, if you're lucky (perhaps some oddball stuff with SSE but there you get 4-8 ops/cycle max, and it's also floating point only). Perhaps some RISC or VLSI architecture you're referring to?
Billy ONeal
@Billy: GPU, not CPU.
Potatoswatter
@Potatoswatter: Ah. That makes sense. Does CUDA or AMD's equivalent provide integer operations? For some reason I thought it was all single precision floating point...
Billy ONeal
@Billy: Nope, integers are first class. Flow control and array indexing would be a real pain without them, although I'm sure there's an architecture out there that has done it. The slowness of division would probably render my calculation wrong by a fair factor, though. (Of course, division could easily be optimized out here, but the point here is handling stupid programs.)
Potatoswatter
@Potatoswatter: Hmm.. that sounds really neat. Going to have to take a look.... :P
Billy ONeal
Oh, I'm an idiot. Re-read the above -- I meant VLIW not VLSI :P
Billy ONeal
A: 

This could take a very long time to run.

Add this to see your progress (though it will take even longer):

for(i=2;i<num;i++)
    {
        if(num%i==0)
        {
            flag=0;
            printf("%d,", num); /* <== show the prime */
            break;
        }
    }

Edit

As others are pointing out, this is the slowest way to count primes. Perhaps the purpose of your assignment is to get you to look up (and implement) faster ones?

egrunin
Not much longer though -- most of the time isn't going to spent actually finding primes. +1
Billy ONeal
-1, don't take offense. not an answer, just a visual to what my comment said over an hour ago.
vol7ron
@vol7ron: um, what? SO lists them both as "11 hours ago". And even if you were right, handing out negatives for duplicates makes no sense.
egrunin
+20  A: 

You aren't doing millions of calculations, you are doing trillions of them.

IsPrime will run in O(n) time, that is it will perform 2 million instructions just to determine that single number. Doing that sort of thing two millions time will take way too long.

To do this you really want to use something like: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes, which can much more efficently determine all of the prime numbers in a particular range.

Winston Ewert
+1 for Sieve_of_Eratosthenes
Billy ONeal
Actually two million squared is only four trillion, not anything near quadrillion.
Billy ONeal
@Billy my bad, off by one error
Winston Ewert
Yeah yeah Sieve is cool, but this whole sum the primes question has been asked a million times and there are some darn fast answers out there. In particular the Sieve is limited in that you can look at the first 2M numbers easily, but if you wanted the first 2M primes - then it gets a bit trickier. A fast python prime generator is something I would recommend looking at. Scan the whole thread and prepare to learn something new. http://stackoverflow.com/questions/567222/simple-prime-generator-in-python
Hamish Grubijan
@Hamish: I don't think a generator written in Python would be an acceptable answer to someone in a class using C. Moreover the question is tagged as C. We don't particularly care about your language preference here.
Billy ONeal
@Hamish: As long as you're okay with getting *at least* 2 million primes, it's possible to calculate an upper bound for the nth prime - so you can just find that value and use it with your sieve. See http://stackoverflow.com/questions/1042717/is-there-a-way-to-find-the-approximate-value-of-the-nth-prime for details.
Michael Madsen
@Billy ONeal, this is not about a language, but a new concept when it comes to primes. If the asker was not lazy and looked around for other questions about primes, he would have found great answers on SO. I am hoping to benefit the future readers, and not that eager to help with homework, particularly when it is a problem that was given to probably literally a million of computer science students over the last few decades.
Hamish Grubijan
@Hamish: If not about language, then why was Python even brought up? Certainly it was referenced nowhere else in this thread. I'm sorry if it was a knee jerk reaction -- I'm just getting tired of every time someone asks a question getting a response "well just write it in X instead" instead of actually trying to answer the original question. That might have not been your intention, but that's how it came off. Sorry if I misunderstood.
Billy ONeal
+3  A: 

As others have said, it will take a long time. One alternate and interesting approach is the Sieve of Eratosthenes. You can read about it at:

http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes

Basically you initialize an array with the numbers 2...2 million. The lowest number not yet processed is prime. Then, you remove all multiples of this number from the array and continue. It will run much faster than what you have.

Nathan S.
I suspect that the only reason this answer doesn't have tons of upvotes is that @Winston had essentially the same answer but about 4 minutes earlier.
Billy ONeal
Looks like it. I checked that no one had posted it before I looked up the link and answered, but I guess I wasn't the only one with the same idea at that time!
Nathan S.
+3  A: 

Off-beat answer

gotoxy(25,25);

Do you run your program in text mode? If the text screen is only 80 x 25, and if the 25th line is occluded by some other things, then chances are you won't see any change in the text screen.

rwong
Odds are that the 25th line is accessed with `gotoxy(25,24)`, so he's actually displaying off-screen!
Gabe
25,25 doesnt take you somewhere near middle of the screen?
fahad
@fahad: Only if your terminal is 50 lines long. Most terminals are only 25 lines total (at least "standard ones").
Billy ONeal
A: 

Your program results in integer overflow, you could use long long to fix it.

Also, your algorithm for checking if a number is prime is not very good. Another way that is just as easy is to test the numbers 2 to the square root of the number. You only have to check up to the square root of the number to determine if it is prime.

syork
A: 

A simple change would show you how fast your program is running, and how much work it has to do. It is easy to print out your status around every 100 iterations. (Or you could set it to 1000, or 10000 iterations.)


Recognize that you could DOUBLE the speed of your loop in IsPrime.
After you check 2, you only need to check odd numbers, and could advance with i+=2 instead of i++.

If you're concerned about speed, why are you spending so much time checking even numbers? (note that once you start doing only odd-numbers, you also need to change the output test to be a odd number)

You can DOUBLE the speed of the loop in main as well by also avoiding even numbers there. (again, you have to special-case 2, then use i+=2, starting at 3 to get 3, 5, 7, 9....)

By making the loop in IsPrime run twice as fast, and making the loop in main run twice as fast, this should make your program go 4X faster. (if it would've taken an hour before, now it'll be 15 minutes.)


The other big speed improvement you could make is only running the loop to sqrt(num), instead of num

Since I hate bringing in floating point functions, such as sqrt, I instead suggest a close approximation that will stop within 100 iterations of passing the sqrt boundary, and also show status updates regularly.

if (num%2 == 0)
{
    flag=0;
    return flag;
}

/* Now that we checked 2, we only need to check odd numbers from now on. */
for(i=3;i<num;i+=2)
{
    if (i%101 == 0)
    {
        printf("i is %d out of %d\n", i, num);
        if (i*i > num)
        {
            break;  /* If you pass the sqrt boundary, quit. */
        }
    }

    if(num%i==0)
    {
        flag=0;
        break;
    }
}

P.S. I put this code into a C# project (minor porting). Granted, this was now running on a 64-bit OS, with a better compiler and 2.8GHz CPU.
It ran in less than 20 seconds.

abelenky
why do you prefer to calculate the square of the index instead n/101 times instead of calculating the square root of n once?
aaronasterling
The question is tagged Turbo-C. In that compiler, the floating-point library is separate, and linking it in drastically increases the executable size, and even restricts you to CPUs with an FPU (yes, back in the day, not all CPUs had FPUs). There is definitely a good argument to be made for one sqrt operation, but I suspect the formatted printf every 100 statements is MUCH more of a CPU hog than a simple integer multiplication. Adding the integer multiply is more "my style", and very cheap relative to the other operations in the same scope.
abelenky
This answer optimizes things, but the problem here is really that the OP used the wrong algorithm to begin with, not that his current solution is a necessarily slow implementation of that algorithm.
Billy ONeal
@Billy: I agree, but I answer the question asked. I would prefer to say, "You're doing it wrong... redesign your algorithm from scratch", but that won't help the student very much.
abelenky
@abelenky: In what way would that not help the student?
Billy ONeal
+1  A: 

you can use sieve methods to do this as well that aren't much more complicated than what you are using. The idea is to pick the first n consecutive prime numbers and use them to construct a sieve. I discuss it (with proofs) in my answer to another question and Sheldon L. Cooper provides an implementation in his. I don't think he got enough upvotes for doing so (I already got 'nice answer', so maybe you could help him out on that.

so after you calculate the sieve numbers, you only need to test for divisibility by numbers that line up with the sieve and are smaller than the square root of n.

aaronasterling
+2  A: 

As others have said: check the limits of your implementation

If TurboC++ has <limits.h>, those implementation limits have a corresponding macro defined in that header

#include <limits.h>
#include <stdio.h>
int main(void) {
    printf("int goes from %d to %d.\n", INT_MIN, INT_MAX);
    printf("long goes from %ld to %ld.\n", LONG_MIN, LONG_MAX);
    return 0;
}

If that fails you need to "calculate" the limits yourself. I'm switching to unsigned because there's no overflow problem with them, and I only need to "calculate" the upper limit (the lower limit is 0)

#include <stdio.h>
int main(void) {
    unsigned u;
    unsigned long lu;

    u = -1; lu = -1;
    printf("unsigned ints go all the way to %u\n", u);
    printf("unsigned longs go all the way to %lu\n", lu);
    return 0;
}

On my system, the 1st program outputs

int goes from -2147483648 to 2147483647.
long goes from -9223372036854775808 to 9223372036854775807.

and the 2nd program outputs

unsigned ints go all the way to 4294967295
unsigned longs go all the way to 18446744073709551615
pmg
I'm assuming that you actually produced that output from something like GCC, because TurboC and friends produce 16 bit applications, which (of all things) require NTVDM to actually execute. (`short` is 16 bits, `int` and `long` are 32 bits)
Billy ONeal
Yes, I built and run that on a 64-bit Linux. But the results on my machine are not the important part: the important is the results on OP machine (*I had a Virtual Machine with DOS 6.2 on my previous installation. Maybe I'll reinstall that here too*)
pmg
My int is way to small than yours
fahad
I wish my `unsigned long long`s were 128 bits: ... all the way to 340282366920938463463374607431768211455 (39 digits)
pmg
+2  A: 

Still no comment/answer about the constant except an "Epic"...

#define TWO_MILLION 2*1000*1000

This is bad. When you change the value later, you either have a name-content-mismatch:

#define TWO_MILLION 5*1000*1000

or you rename it to

#define FIVE_MILLION 5*1000*1000

and need to change it everywhere you've used it. Don't name your constants after the content, this just turns your magic numbers into magic names. Name them after their meaning, e.g. MAX_NUMBER UPPER_LIMIT RANGE_TO_TEST or whatever fits best.

Secure
Constants are rarely changed.
fahad
@fahad: Then why use a define at all and not write the number itself in the code? It's considered bad programming practice. The comment above with "Epic" with 20+ upvotes refers to the fact that such code has a high probability for being featured on thedailywtf.com. Browse the articles there, you will find enough examples.
Secure
I don't think people would've objected to: #define UPPER_LIMIT 2*1000*1000 // Two MillionThen you could change UPPER_LIMIT to be any other number, without pervasive code changes.
abelenky
Thanks,for explaining how to name a constant
fahad