
A function to sleep a 1000 years: explained - jandeboevrie
https://bowero.nl/blog/2019/12/14/a-function-to-sleep-a-1000-years-explained/
======
iforgotmypass
I guess I am the only one missing the point (disliking this as a code golf
challenge) and cringing that the solution does not sleep for a precise 1000
years and overthinking that various other rules are not being taken into
account (e.g. leap years, extra seconds per year, etc.).

~~~
mjevans
Given the context of 'code golf' I don't mind the submitted solution being
'close enough', it even seems like the programmer in question was precise in
their wording (if they were quoted properly).

Overall the thought of a pinned register being software updated once every 7
seconds for near a thousand years is the worst part.

I stand corrected; I'm so used to seeing these unrolled (which hopefully the
hypothetical compiler's done) that I didn't consider the stack implications;
that's the most cringy part.

------
ddevault
While we're nit-picking, this also doesn't account for a lot of problems which
are inevitable on a 1,000 year scale, such as the lifetime of the computer's
parts, dealing with power outages, staffing for the long-term upkeep of the
system, etc.

~~~
perl4ever
That line of code is not beautiful, it's obscene.

At the very least, anything that's intended to last a long time should be
written in the simplest, clearest, self-explanatory manner so as to at least
give reasonable confidence it's correct.

Not to mention, 952 years is a lousy approximation of a millennium.

    
    
      const yearSeconds = 31556926
    
      for i = 1 to 1000
        sleep yearSeconds
    

Or, use some calendar library to get the exact number needed.

~~~
contravariant
Why wait for a tropical year though? Surely most people will assume it waits
for a calendar year?

Of course, even without leap seconds, this severely complicates the issue
since you'd first need to figure out the number of leap days in the next 1000
years, which is unfortunately not fixed since 1000 is not a multiple of 400.

~~~
perl4ever
I reconsidered the spirit of the thing, which is obviously to use C and not to
use large constants or external libraries. But I still think 95% accurate is
terrible, so I posted a 99.99% solution in C.

Edit: I used the tropical year number without thinking about it, but (a) the
difference is de minimus compared to being 5% off, and (b) I consider it
undefined whether the Gregorian calendar year _really is_ different, because
who's to say we won't have an adjustment to the leap year cycle in the very
long run to make them converge?

------
joveian
Not thread-safe. Also, from Alex in the comments: "Sounds good! Although
probably we will run out of stack waay before that".

~~~
sn
It won't run out of stack space with a high enough optimization level so that
it uses tail recursion.
[https://en.wikipedia.org/wiki/Tail_call](https://en.wikipedia.org/wiki/Tail_call)

You can try this yourself by compiling:

#include <stdio.h>

int i = 0; int x() {--i && x(printf("x"));} int main() {x();}

using gcc with and without '-02'.

------
perl4ever
You want obfuscated, I'll give you obfuscated:

    
    
        void
        f (int i, int j)
        {
            int k = j;
            
            k <<= 2;
            k += j;
            k <<= 3;
    
            if (--i)
                while (--k)
                    f(i, j);
            else
                sleep(k);
        }
    
        int
        main ()
        {
          f (3, 'O'); /* Sleep for 1000 years */
    
          return 0;
        }
    

...this should solve your stack overflow problems _and_ be 99.9% accurate.

~~~
perl4ever
(IMO enterprise grade C code should not have types other than int, use numbers
larger than 2^15-1, or constants with more than one digit/character. This is,
I'm sure, the best way to avoid undefined behavior and concomitant nasal
demons)

~~~
perl4ever
Here's a more user-friendly version with self-explanatory parameters:

    
    
      f(i, j, k, l) { for (j = (j << 2) + j << 3; i + 1 && --j; f(i - 1, k, l, l)); sleep(j); }
    
      int
      main ()
      {
        f(1, 'O', 'O', 'O'); /* Sleep for 1000 years */
      }

------
joelkevinjones
Another problem is that it makes the assumption that an int is 32 bits. The
C89 standard certainly doesn't promise that.

------
Dylan16807
> With this, we have proven that this beautiful line of code is correct!

I wouldn't say 'correct', exactly. Not just int size, it depends on undefined
behavior and a moderate level of compiler optimizations at the same time. Good
luck there.

------
stopreformation
It relies on undefined behavior since signed integer overflow is undefined.

------
xg15
Apart from showing off syntax tricks, what exactly was the reason to write
f(sleep(7)) instead of e.g. sleep(7);--i&&f()? Just minimizing the character
count?

~~~
esnard
The original challenge [0] was submitted as a "code-golf" challenge, which
means that the solution needed to solve the problem in the fewest bytes of
source code.

There are a lot of tricks to minimize the character count, and replacing
a();b() with b(a()) is one of them.

[0]:
[https://codegolf.stackexchange.com/q/196917/38454](https://codegolf.stackexchange.com/q/196917/38454)

~~~
xg15
Ah, that makes sense. Thanks.

