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*/
/*Print result header*/
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);}
/*Use fast scrolling instead.*/
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.