# Here's one for the mathematically curious (not a game)

The following program computes PI to any number of decimal places up to approximately 8127:

``````/* This program computes PI to the specified number of decimal places.
It is only accurate to 32372 decimal places; digits after that are wrong.
Based on the one-line spigot algorithm that calculates exactly 14999 decimal places:
a[52514],b,c=52514,d,e,f=1e4,g,h;main(){for(;b=c-=14;h=printf("%04d",e+d/f))for(e=d%=f;g=--b*2;d/=g)d=d*b+f*(h?a[b]:f/5),a[b]=d%--g;}
attributed to Dik T. Winter of Centrum Wiskunde & Informatica in Amsterdam (deceased).
Created 25 Jun 2019 Frank Prindle

Ported to Ringo/Makerphone 8 Dec 2019 Frank Prindle (updated 13 Dec 2019 for return to firmware)
(updated 16 Dec 2019 to use Ringo Library 1.0.2; restore splash screen; support home button popup)
Use A key for the enter key.
Use * or # key for the backspace key.
Use B key during scrolling to pause scrolling; or before numeric input to reboot firmware.
Maximum decimal places appears to be approximately 8127 (cannot allocate contiguous
space on heap larger than approximately 113792 bytes).
*/

#include <MAKERphone.h>
#include <stdio.h>
#include <stdlib.h>

MAKERphone mp;

int *a; /*Array size 3.5 times number of significant digits
Needs 32 bits, so must be long int for 16-bit compilers*/

void setup()
{
mp.begin(1);
}

void loop()
{
int digits;
int places=0;
int awords;

mp.update();
mp.display.setTextColor(TFT_YELLOW);
mp.display.setTextFont(1);
mp.display.fillScreen(TFT_BLACK);
mp.display.setCursor(0,0);
mp.display.setScrollRect(0, 0, mp.display.width(), mp.display.height());

/*Query user for number of decimal places.*/
mp.display.print("How many decimal places do\nyou want PI to? ");
while(!mp.buttons.released(BTN_A))
{
mp.update();
if(mp.exitedLockscreen)return; // If returning from lock screen, start over.
if(mp.buttons.released(BTN_B) && !places) mp.loader(); // B reboots firmware if available
if(mp.buttons.released(BTN_HOME)) return; // If returning from popup menu, start over
for(int i=0; i<12; i++) if(mp.buttons.released(i))
{
if(i==10) places = places*10;
else if(i==9 || i==11) places = places/10;
else places = places*10 + (i+1);
mp.display.fillRect(100,8,50,8,TFT_BLACK);
mp.display.setCursor(100,8);
mp.display.print(places);
}
}
if(!places) places = 1;
mp.display.fillScreen(TFT_BLACK);
mp.display.setCursor(0,0);

/*Make array a the proper size based on number of decimal places requested.*/
digits = places+1; /*decimal places to significant digits of PI*/
digits = (digits+3)&0xfffffffc; /*force digits to multiple of 4*/
awords = 7*digits/2; /*3.5 times number of digits*/
a=(int *)malloc(awords*sizeof(int));
if(a==NULL) {mp.display.print("Not enough memory\n"); delay(100); mp.update(); delay(1000); return;}

/*Initialize array elements to 2000 (a[0] is not used).*/
for(int i=1;i<awords;i++) a[i]=2000; /*10000/5*/

mp.display.print("PI to ");
mp.display.print(places);
mp.display.print(" decimal places\n");
mp.update();

/*Compute PI to digits significant digits (digits-1 decimal places).*/
unsigned int d=0;
int c;
int count = 0; /*Not part of the computation, just for formatting*/
for(c=awords; c>0; c-=14)
{
/*This is the core of the algorithm for producing the next 4 digits of PI.*/
d=d%10000;
int e=d;
int b;
for(b=c-1; b>0; b--)
{
int g=b*2-1;
d=d*b+10000*a[b];
a[b]=d%g;
d=d/g;
}

/*Four digits of PI available... format them nicely for printout.*/
char str[5];
sprintf(str,"%04d",e+d/10000);
for(int i=0;i<4;i++)
{
mp.display.print(str[i]);
if(count && count%5==0)mp.display.print(' ');
if(count%20==0)
{
if(count)
{
mp.buttons.update(); while(mp.buttons.states[BTN_B]) mp.update(); // Pause scrolling
mp.display.pushSprite(0,0);
if(count>=300 && count!=places)
{
/*This would be for smooth scrolling, but it's annoyingly slow.*/
//for(int i=0; i<8; i++) {mp.display.scroll(0,-1); mp.display.pushSprite(0,0);}
mp.display.scroll(0,-8);
mp.display.setCursor(0, mp.display.height()-8);
mp.display.print("  ");
}
else mp.display.print("\n  ");
}
else mp.display.print('.');
}
if(count==places)break;
count++;
}

/*Loop for generation of more 4 digit results.*/
}

/*All requested decimal places printed. Free array a but leave results displayed until
Button B is pressed or returning from lock screen.*/
free(a);
while(!mp.buttons.released(BTN_A)) {mp.update(); if(mp.exitedLockscreen || mp.buttons.released(BTN_HOME))return;}
}
``````

It is based on this one-line spigot algorithm that calculates PI to exactly 14999 decimal places:
`a[52514],b,c=52514,d,e,f=1e4,g,h;main(){for(;b=c-=14;h=printf("%04d",e+d/f))for(e=d%=f;g=--b*2;d/=g)d=d*b+f*(h?a[b]:f/5),a[b]=d%--g;}`
attributed to Dik T. Winter of Centrum Wiskunde & Informatica in Amsterdam (deceased).

• Use A key for the enter key.
• Use * or # key for the backspace key.
• Use B key to pause scrolling.
• Use B key before entering digits to reboot firmware.
• Use Home key to bring up in-game popup menu.

You can compile and upload this to the Makerphone with the Arduino IDE and run it. The challenge is, of course, to comprehend how the algorithm (the essence of which is the code from lines 88 to 98) manages to produce the digits of PI. I certainly don’t know how it works, only that it does work. Have fun with this.

N.B.: If you doubt the correctness of the results, you can find definitive values for PI on the internet; for example: https://www.angio.net/pi/digits.html

Update: Added one line of code on 13 Dec 2019 so that B will reboot firmware partition if pressed before entering number of decimal places.

Update 2: Used Ringo Library 1.0.2 (linked in bin file); restored the splash screen; now supports home button popup menu.

2 Likes

Wow, that’s super cool Frank!

You’ve really done some quality work here.
Just couple of things on your program - it would be cool if you had an option of going back to the start, clear all the memory and re-enter the number of decimals you want without restarting the phone.

Also, if you could scroll to see all of the decimals, that would be super sweet!

Nevertheless, great work!

Robert

You only need to press the A button (enter) after viewing the results to restart and enter a new number of decimal places.

That would require memory to save the text, but it’s all been used up by array a when a large number of places is computed. At least you can hold down the B button to pause scrolling. Besides, the interesting digits are the ones at the end anyway; you can always see earlier ones by asking for fewer places.

For some reason the first one didn’t work for me.

Anyway, I’ve compiled it into a bin and added the extra menu flag (when pressing the home button) so it can now be used as an app.

The other one could be done, but some reorganization of data would be needed. Not impossible, but yes, not really that necessary.

Pi.zip (650.0 KB)

Hmmm… your bin file has a lot less available memory (can’t even do 7500 decimal places, whereas mine (when compiled with the Arduino IDE [with optimization -03] and linked with the 1.0.0 library) can go to 8127 decimal places. Perhaps you used a different compiler or the 1.0.2 or 1.0.3 library and that makes a difference. If I allocated enough memory to cache the display before allocating “a”, that would also cut into the max number of decimal places possible; I was aiming to maximize that.

Even flashing your bin file, for me pressing A after all digits are displayed returns from the loop and therefore starts over from the top of the loop. The last line in the program does exactly that, waits for A.

I had disabled that menu because when that menu is dismissed, the screen is not refreshed until A is pressed.

Guess the button was faulty at the time, or didn’t work once - works perfectly now!

A lot of things can play a part there - we can try to even ramp up that number as far as it goes, why not?

Well I get it, but then it’s not possible to return to the home screen (if you use it like an app) so it really loses its function. Nevertheless, pretty cool thing!

I added one line of code to the program in the first post so that pressing B before entering the number of decimal places will reboot the firmware (when loaded as an app). Still goes out to 8127 decimal places when compiled by Arduino IDE and linked with Ringo library 1.0.0. Here’s my bin: PI.bin

1 Like

Now that CircuitMess has released Ringo Library 1.0.2 to install in Arduino IDE, I rebuilt the bin file with that library. While I was at it, I restored the splash screen shown during initialization and re-enabled the home button popup menu now that I figured out how to restart when that menu is dismissed. I once again modified the source code in the first post (note that the core algorithm code has now been pushed down slightly to lines 88-98). The (hopefully final) bin file is in the same place: PI.bin

1 Like