1

How can I run a loop in c for a very large count in c for eg. 2^1000 times?

Also, using two loops that run a and b no. of times, we get a resultant block that runs a*b no. of times. Is there any smart method for running a loop a^b times?

Nitin Labhishetty
  • 1,290
  • 2
  • 21
  • 41
  • Somehow you would have to implement your own "big integer" type, and at least three operations: attribute a big number, decrease it, and test if it is zero. Using several nested for's is the crudest method (the set of all loop counters is your 'big number'). – epx Feb 25 '14 at 15:55
  • I need this in a situation where I have to ignore 2^n lines of input, is there some other way to do that without iterating? I'm taking input from standard input using scanf. – Nitin Labhishetty Feb 25 '14 at 15:58
  • 1
    Loop is not completed while alive probably. – BLUEPIXY Feb 25 '14 at 16:02
  • 2
    2^1000 times? Let's assume that your loop doesn't do anything and the CPU manages to run 2^32 loop iterations per second (close enough to reality). There's around 2^20 seconds in a year. That gives you 2^52 iterations per year. I don't think this something you want to do. – Art Feb 25 '14 at 16:04
  • Yes, you are right. I definitely do not want to run my program for that long. But if I have two lines of input and 2^n lines of trash between them, how do I skip past them? – Nitin Labhishetty Feb 25 '14 at 16:06
  • Any recursive solution will most likely result in a stack overflow even for relatively small values of `a` and `b`. For a pure iterative solution, you will need to implement some sort of "BigInteger class" (with partial functionality, such as `mul` and `sub`, by the minimum). – barak manos Feb 25 '14 at 16:13
  • In answering some of these comments, you've added some relevant key points to what _you really want to do_, i.e. skip a bunch of input between addressing those you want to address. Can I suggest you edit your post to say that? – ryyker Feb 25 '14 at 16:13
  • 2
    I doubt that "n" will be more than 64. 2^64 is enough to solve your problem if you were processing all the data on the planet in 2006 if the data was only newlines. So just use uint64_t. If you are processing all the newlines on this planet today you might need a bigger datatype, see if your compiler supports it. – Art Feb 25 '14 at 16:14
  • You don't have 2^1000 lines of input. Unless you mean xor. – Kevin Feb 25 '14 at 16:16
  • If your problem is really that big that 64 bit ints aren't enough I recommend reading this paper: http://arxiv.org/pdf/astro-ph/9912202/ It shows that thanks to Moore's law for any computation you need to do that takes more than 26 months it's always better to wait around a do nothing for a while until better and cheaper hardware is invented. – Art Feb 25 '14 at 16:20
  • 3
    @BLUEPIXY - not a constraint. The box/loop could be bequeathed to future generations to continue to monitor its run. The answer is gonna be 42, anyway:) – Martin James Feb 25 '14 at 16:48

5 Answers5

2

You could loop recursively, e.g.

void loop( unsigned a, unsigned b ) {
    unsigned int i;
    if ( b == 0 ) {
        printf( "." );
    } else {
        for ( i = 0; i < a; ++i ) {
            loop( a, b - 1 );
        }
    }
}

...will print a^b . characters.

Frerich Raabe
  • 90,689
  • 19
  • 115
  • 207
  • 3
    This recursion will most likely result in a stack overflow even for relatively small values of `a` and `b`. – barak manos Feb 25 '14 at 16:08
  • @barakmanos Are you sure? The maximum recursion depth is `b`, in a 32bit build system I would expect the function to consume at most 12 bytes of stack space (two arguments and the internal `i`). You could easily compute `loop(2, 1000)` I think. – Frerich Raabe Feb 25 '14 at 16:11
  • I dunno, looks pretty deep to me :) ... but then again, I come from the embedded side of the map, so I tend to think that way sometimes. In any case, even if it works for 2^1000, it is not "sustainable" for **every** value of `b`, as you probably understand yourself. Any recursive solution will eventually result in a stack overflow for some given value of `b`. For a pure iterative solution, you will need to implement some sort of "BigInteger class" (with partial functionality, such as `mul` and `sub`, by the minimum). – barak manos Feb 25 '14 at 16:18
  • @barakmanos Sure, but even with some "BigInt" solution you will eventually run out of memory to represent the digits so you cannot do it for *every* value of `b` either. ;-) To determine the recursion depth, notice how `loop` calls itself: with every-decreasing values of `b` until it hits zero, the base case. – Frerich Raabe Feb 25 '14 at 16:31
  • Well, you're right. A large amount of memory will be spent either way. Function-call operations will be saved when using an iterative solution, but you'll have to use "BigInt Sub" operations instead. So there's no performance advantage either. I guess that by minimum, it requires O(a^b) bits of memory and O(a^b) operations, whether it's a recursive or an iterative solution. – barak manos Feb 25 '14 at 16:39
  • @barakmanos "Any recursive solution will eventually result in a stack overflow for some given value of `b`." is patently false. A stack overflow is an implementation detail. There will be no stack overflow if the compiler doesn't make use of those implementations details. – R. Martinho Fernandes Feb 25 '14 at 16:54
  • @R. Martinho Fernandes: I believe that recursion is a programming technique which is by definition a stack-based (or LIFO-based) implementation. So while the term `stack` may be seen as generic, the term `recursion` is very specifically defined. – barak manos Feb 25 '14 at 17:10
  • That's still irrelevant. Many compilers implement various recursive functions as loops. There is no stack overflow unless a compiler implements recursion using a stack that can overflow, which it doesn't have to. – R. Martinho Fernandes Feb 25 '14 at 17:12
  • @barakmanos The term `recursion` is indeed very specially defined: it means that a function references itself. In particular, the definition does not include how this feature is implemented. A very common optimization for implementing recursion is [tail-call optimization](http://stackoverflow.com/questions/34125/which-if-any-c-compilers-do-tail-recursion-optimization?lq=1). – Frerich Raabe Feb 25 '14 at 17:21
1

While I cannot answer your first question, (although look into libgmp, this might help you work with large numbers), a way to perform an action a^b times woul be using recursion.

function (a,b) {
   if (b == 0) return;
   while (i < a) {
     function(a,b-1);
   }
}

This will perform the loop a times for each step until b equals 0.

stmfunk
  • 663
  • 5
  • 20
1

Regarding your answer to one of the comments: But if I have two lines of input and 2^n lines of trash between them, how do I skip past them? Can you tell me a real life scenario where you will see 2^1000 lines of trash that you have to monitor?

For a more reasonable (smaller) number of inputs, you may be able to solve what sounds to be your real need (i.e. handle only relevant lines of input), not by iterating an index, but rather by simply checking each line for the relevant component as it is processed in a while loop...

pseudo code:

BOOL criteriaMet = FALSE;
while(1)
{
    while(!criteriaMet)
    {
         //test next line of input
         //if criteria met, set criteriaMet = TRUE;
         //if criteria met, handle line of input
         //if EOF or similar, break out of loops
    }
    //criteria met, handle it here and continue
    criteriaMet = FALSE;//reset for more searching...

}
ryyker
  • 22,849
  • 3
  • 43
  • 87
  • Thanks, though this was what I needed, I was more interested in a large(known) bound iteration hence I asked this question. Thanks a lot anyway, your answer is really helpful :) – Nitin Labhishetty Feb 25 '14 at 16:30
  • 2
    You are welcome. I am not sure that your original post made that clear, but some of your responses to comments kind of brought it out. Nice question, it got people thinking. – ryyker Feb 25 '14 at 16:32
  • and yes, I realized that 2^1000 is too big. Need to do my math more carefully next time. – Nitin Labhishetty Feb 25 '14 at 16:32
  • @ryyker Implementing 2^1000 steps using recursion is perfectly fine once you realize that the recursion depth is only O(n) on the exponent. – Frerich Raabe Feb 25 '14 at 17:25
  • 1
    @FrerichRaabe - I err'd in buying into into the _overflow_ assumptions without verifying they were correct. I've since deleted my comment to remove that indictment. Yours is a good answer. It just _seems_ more efficient to process only input of interest, by-pass all the rest. (rather than recurse through all input) Perhaps that's another assumption I should verify when I have some free time. – ryyker Feb 25 '14 at 22:46
0

Use a b-sized array i[] where each cell hold values from 0 to a-1. For example - for 2^3 use a 3-sized array of booleans.

On each iteration. Increment i[0]. If a==i[0], set i[0] to 0 and increment i[1]. If 0==i[1], set i[1] to 0 and increment i[2], and so on until you increment a cell without reaching a. This can easily be done in a loop:

for(int j=0;j<b;++j){
    ++i[j];
    if(i[j]<a){
        break;
    }
}

After a iterations, i[0] will return to zero. After a^2 iterations, i[0],i[1] will both be zero. AFter a^b iterations, all cells will be 0 and you can exit the loop. You don't need to check the array each time - the moment you reset i[b-1] you know the all the array is back to zero.

Idan Arye
  • 12,402
  • 5
  • 49
  • 68
-1

Your question doesn't make sense. Even when your loop is empty you'd be hard pressed to do more than 2^32 iterations per second. Even in this best case scenario, processing 2^64 loop iterations which you can do with a simple uint64_t variable would take 136 years. This is when the loop does absolutely nothing.

Same thing goes for skipping lines as you later explained in the comments. Skipping or counting lines in text is a matter of counting newlines. In 2006 it was estimated that the world had around 10*2^64 bytes of storage. If we assume that all the data in the world is text (it isn't) and the average line is 10 characters including newline (it probably isn't), you'd still fit the count of numbers of lines in all the data in the world in one uint64_t. This processing would of course still take at least 136 years even if the cache of your cpu was fed straight from 4 10Gbps network interfaces (since it's inconceivable that your machine could have that much disk).

In other words, whatever problem you think you're solving is not a problem of looping more than a normal uint64_t in C can handle. The n in your 2^n can't reasonably be more than 50-55 on any hardware your code can be expected to run on.

So to answer your question: if looping a uint64_t is not enough for you, your best option is to wait at least 30 years until Moore's law has caught up with your problem and solve the problem then. It will go faster than trying to start running the program now. I'm sure we'll have a uint128_t at that time.

Art
  • 19,807
  • 1
  • 34
  • 60
  • This discussion is long over in the comments. I also admitted that the value I mentioned in the question is way too large for practical purposes but the essence of the question is iterating for large values, especially when given in the form of a^b which the other answers have explained quite well, so please go through other activity before giving such geeky sarcastic answers. – Nitin Labhishetty Feb 25 '14 at 22:18
  • It's not sarcasm. Just facts. You're obviously new at this, so I'm just pointing you in the right direction so you don't need to worry about this problem because it isn't a problem. – Art Feb 25 '14 at 23:24
  • Regarding your statement: _wait at least 30 years until Moore's law has caught up with your problem_. It is likely that ***[Moore's Law](http://gcn.com/blogs/emerging-tech/2013/09/moores-law.aspx)*** won't last that long. (self proclaimed at its inception by Moore himself, and since then by many others) And - Its its not the content you offer, but the way you stated it that may cause some to take pause. Personally, I found it interesting. – ryyker Feb 26 '14 at 01:23
  • @ryyker Oh, of course. That was mostly a joke in reference to the classic paper ["The effects of Moore's law and slacking on large computations."](http://arxiv.org/pdf/astro-ph/9912202/). Moore's law hasn't been really doing much for loops with large counts in the past few years since most of the development has been in parallelism and not getting a single core faster. – Art Feb 26 '14 at 06:05