5

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;
}
abelenky
  • 58,532
  • 22
  • 99
  • 149
  • 4
    "old Turbo C++ compiler" 1. WHY OH WHY OH WHY OH WHY? 2. Isn't that a C++, not a C question? – Billy ONeal Oct 04 '10 at 02:38
  • 25
    Epic: #define TWO_MILLION 2*1000*1000 – karlphillip Oct 04 '10 at 02:39
  • 4
    My course plan of the university is outdated. –  Oct 04 '10 at 02:40
  • 1
    Well, make it output something every 100 or 1000 or 10000 operations. Also, I suspect that you need a `BigInt` to hold the result and not overflow You could also write a '.' every 10th time you find a prime, but make sure to redirect that to a file to keep speed decent. Then watch the size/content of the file separately. You might want to speed up the primality test by looking up to sqrt(N) only. – Hamish Grubijan Oct 04 '10 at 02:40
  • 1
    if you're curious about output, why don't you just cout in the middle of the loop for visual feedback? – vol7ron Oct 04 '10 at 02:41
  • I gave a break to my program after about 5 minutes and checked the watches at i which was too small as compared to the time. –  Oct 04 '10 at 02:42
  • @fahad: That doesn't mean you need to use an archaic compiler which cannot even produce binaries which run on any 64 bit version of windows. C or C++ are still C or C++, and free compilers (msvc, MinGW) are available which beat the pants off Turbo C and Turbo C++ for both standards compliance and execution speed of compiled code. – Billy ONeal Oct 04 '10 at 02:43
  • btw why are you using an `int` for the flag instead of a `bool`? – vol7ron Oct 04 '10 at 02:43
  • @vol7ron: C has no `bool` datatype. (C99 has _Bool, but that's another story..) – Billy ONeal Oct 04 '10 at 02:44
  • Time how long it takes to do 100 calculations, then that will give you an average for how much it will take to do 1 (time/100), then multiply by 2m to see how long it takes. – James Black Oct 04 '10 at 02:49
  • @JamesBlack: because of `O(n^2)`, it is more accurate to time from 1999901 to 2000000, and then multiply by 0.5 * (2000000 / 100) to get the estimate. – rwong Oct 04 '10 at 02:53
  • waiting..15 minutes and the loop is still not near to 2 million lol –  Oct 04 '10 at 03:14
  • Two million is not that big of a number, but your algorithm is O(n**2). So if it takes 2 minutes to do 1 million, it will take 4 minutes gf – jrockway Oct 04 '10 at 03:21
  • 2
    I've never seen `int`, `unsigned`, and `long` all used in the same declaration before! – Gabe Oct 04 '10 at 04:29
  • `Turbo C++` I assumed `c++`. Does anyone still program in `c` anymore? `C++` is becoming even less likely, with `C#` everywhere. – vol7ron Oct 04 '10 at 04:34
  • @rwong - Thank you for the range, I didn't specify a starting point, just the fact that he may want to time in order to know how long it may take to finish. – James Black Oct 04 '10 at 08:22
  • @Karlphilip:Epic?What did you find interesting in that?20 upvotes on that?Why? –  Oct 04 '10 at 14:05
  • @vol7ron: c is still used in many places. C compilers are UNIVERSALLY available on virtually all hardware (the same is not true of C++, and definitely not true for C#). C can give you access to custom hardware. C# can't do that without *lots* of effort. C is great for many things below user-level. – abelenky Oct 04 '10 at 16:26
  • @vol7ron: 1. there are still very large systems *cough* UNIX and friends *cough* which are written in C, not C++. Perhaps in your narrow set of programs (those which run on Microsoft Windows) C# has become more common. But in terms of number of lines of code actually operating keep in mind that C# runs on only 3 percent of computers or less. You won't see it on, for example, a car microcontroller or cell phone or Kindle. But you'll almost certainly find C there. – Billy ONeal Oct 04 '10 at 17:58
  • http://projecteuler.net/index.php?section=problems&id=10 there are many other questions related to problem 10 as well on here: http://stackoverflow.com/search?q=project+euler+10 – Ron Warholic Oct 04 '10 at 19:50
  • @Gabe:Do you find them using all at once unneccessary? –  Oct 04 '10 at 22:34
  • fahad: Just `unsigned long` is sufficient. – Gabe Oct 04 '10 at 23:57
  • @Gabe:even for my old turbo compiler? –  Oct 05 '10 at 04:15
  • fahad: The first compiler I bought was Turbo C++ and I never once typed `long int`. – Gabe Oct 05 '10 at 08:10

10 Answers10

21

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
  • 40,727
  • 10
  • 63
  • 79
  • 2
    Actually two million squared is only four trillion, not anything near quadrillion. – Billy ONeal Oct 04 '10 at 02:49
  • 3
    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 Oct 04 '10 at 02:53
  • @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 Oct 04 '10 at 04:22
  • 1
    @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 Oct 04 '10 at 09:06
  • @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 Oct 04 '10 at 14:10
  • @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 Oct 04 '10 at 17:10
3

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
  • 97,781
  • 45
  • 291
  • 525
  • 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 Oct 04 '10 at 03:12
  • @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 Oct 04 '10 at 04:24
  • @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 Oct 04 '10 at 17:11
  • @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 Oct 04 '10 at 17:23
  • @Potatoswatter: Hmm.. that sounds really neat. Going to have to take a look.... :P – Billy ONeal Oct 04 '10 at 17:49
  • Oh, I'm an idiot. Re-read the above -- I meant VLIW not VLSI :P – Billy ONeal Oct 04 '10 at 17:55
3

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.
  • 5,129
  • 3
  • 39
  • 52
  • 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 Oct 04 '10 at 04:27
  • 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. Oct 04 '10 at 04:53
3

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
  • 5,866
  • 1
  • 20
  • 45
  • 1
    Odds are that the 25th line is accessed with `gotoxy(25,24)`, so he's actually displaying off-screen! – Gabe Oct 04 '10 at 04:27
  • 25,25 doesnt take you somewhere near middle of the screen? –  Oct 04 '10 at 14:07
  • @fahad: Only if your terminal is 50 lines long. Most terminals are only 25 lines total (at least "standard ones"). – Billy ONeal Oct 04 '10 at 17:52
2

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
  • 98,431
  • 10
  • 118
  • 189
  • 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 Oct 04 '10 at 17:53
  • 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 Oct 04 '10 at 20:54
  • My int is way to small than yours –  Oct 05 '10 at 17:25
  • I wish my `unsigned long long`s were 128 bits: ... all the way to 340282366920938463463374607431768211455 (39 digits) – pmg Oct 06 '10 at 00:09
2

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
  • 4,030
  • 1
  • 14
  • 15
  • Constants are rarely changed. –  Oct 04 '10 at 14:06
  • 2
    @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 Oct 04 '10 at 15:42
  • I don't think people would've objected to: #define UPPER_LIMIT 2*1000*1000 // Two Million Then you could change UPPER_LIMIT to be any other number, without pervasive code changes. – abelenky Oct 04 '10 at 21:27
  • Thanks,for explaining how to name a constant –  Oct 04 '10 at 22:36
1

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.

Community
  • 1
  • 1
aaronasterling
  • 61,516
  • 19
  • 116
  • 125
0

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
  • 23,366
  • 5
  • 44
  • 92
  • Not much longer though -- most of the time isn't going to spent actually finding primes. +1 – Billy ONeal Oct 04 '10 at 02:45
  • -1, don't take offense. not an answer, just a visual to what my comment said over an hour ago. – vol7ron Oct 04 '10 at 04:37
  • @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 Oct 04 '10 at 14:31
0

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
  • 36
  • 3
0

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
  • 58,532
  • 22
  • 99
  • 149
  • 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 Oct 04 '10 at 03:14
  • 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 Oct 04 '10 at 04:04
  • 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 Oct 04 '10 at 04:25
  • @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 Oct 04 '10 at 04:31
  • 1
    In what way would that not help the student? – Billy ONeal Oct 04 '10 at 04:45