Jump to content

Code Explainer -- Underscore Pi


tao

Recommended Posts

This clever program written by Brian Westley calculates π by looking at its own area.  It is one of the winning entries of IOCCC in 1988.

#define _ -F<00||--F-OO--;
int F=00,OO=00;main(){F_OO();printf("%1.3f\n",4.*-F/OO/OO);}F_OO()
{
            _-_-_-_
       _-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
_-_-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
 _-_-_-_-_-_-_-_-_-_-_-_-_-_-_
  _-_-_-_-_-_-_-_-_-_-_-_-_-_
    _-_-_-_-_-_-_-_-_-_-_-_
        _-_-_-_-_-_-_-_
            _-_-_-_
}

 

Getting it to run

Because of an unusual use of the preprocessor, the program will not give correct results when compiled with modern gcc.

% gcc ./westley.c && ./a.out
(...warnings omitted)
0.250

One of the solutions is to use the -traditional-cpp parameter for gcc, as follows:

% gcc -traditional-cpp ./westley.c && ./a.out
(...warnings omitted)
3.141

Here we have it, a nice approximation of π.  But where do we get this value from?

How does it work?

We can ask gcc to perform only the pre-processing and not the actual compilation, by using the -E switch:

% gcc -traditional-cpp -E ./westley.c > expanded.c

This gives us a better view on the code, specifically the F_OO function.  The first line of the function shows us that the chains of minuses and underscores have been turned into something like this (newlines added for clarity):

-F<00||--F-OO--;
--F<00||--F-OO--;
--F<00||--F-OO--;
--F<00||--F-OO--;

We know that every _ is expanded by the preprocessor to -F<00||--F-OO--;.  The trick used here is that a minus before an underscore, -_, would change the expression to say --F<00||--F-OO--;, changing the negation into a pre-decrement.

 

The effect of the code above would be one decrement of OO and four decrements of F, as follows:

 

-F < 00 || --F-OO--; would first check if the negation of F is less than zero.  F has the value of zero at the beginning, so the condition is false.  Therefore, the second part is evaluated, decrementing both F and OO.  Now, both F and OO are equal -1 .

 

--F < 00 || --F-OO--; would first decrement F, and then check if it’s less than zero.  The condition is true now and the second part is not evaluated, so now F equals -2 and OO still equals -1.

 

Examining the code further, it is easy to notice that OO is decremented for every line and F for every occurrence of an underscore in the code.  It is easy to see now that F is the calculated area of the circle and OO is the diameter.

 

Now the code can compute the approximate value of π, from the calculated area and diameter of the circle:

printf("%1.3f\n",4.*-F/OO/OO);

A bit of math

The formula used here derived from the one for calculating a circle area from its diameter:

 

r = \frac{d}{2}

A = \pi r^{2} = \pi \big ( \frac{d}{2} \big) ^{2} = \pi \frac{d^2}{4}

Dividing both sides by \frac{d^{2}}{4}  , we get:

\pi = A \frac{4}{d^{2}}

An exercise for the reader

What would happen if you make the circle in the code bigger?

 

< Here >

Link to comment
Share on other sites


  • Views 1.2k
  • Created
  • Last Reply

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...