\ PI.F
\
\ Revised 2015-02-09 es
\
\ Compute Pi to an arbitrary precision. Uses Machin's
\ formula: pi/4 = 4 arctan(1/5) - arctan(1/239)
\
\ Compile with 16-bit DX-Forth: FORTH - INCLUDE PI.F BYE
\
\ This 16-bit implementation allows up to 45,808 digits
\ to be computed before arithmetic overflow occurs.
\
\ The code can be used on 32-bit targets with appropriate
\ changes:
\
\ 16-bit 32-bit
\
\ 10000 Multiply 100000000 Multiply
\ <# # # # # #> <# # # # # # # # # #>
\ 4 +loop 8 +loop
\ 525 um/mod 1050 um/mod
\ remove 'digits > 45808' warning
\
\ Acknowledgements:
\
\ Roy Williams, Feb 1994
\ J. W. Stumpel, May 1991
\ E. Ford, Aug 2009
\ R. Bishop, Aug 1978
\
\ This code is PUBLIC DOMAIN. Use at your own risk.
empty forth definitions decimal application
0 constant Save \ generate turnkey
0 value power ( adr)
0 value term ( adr)
0 value result ( adr)
0 value size ( n)
variable carry
: Add ( -- )
0 carry !
result 0 size 1- do
i cells over + ( res) dup @ 0
i cells term + @ 0 d+ carry @ m+
( hi) carry ! ( lo) swap ( res) !
-1 +loop drop ;
: Subtract ( -- )
0 carry !
result 0 size 1- do
i cells over + ( res) dup @ 0
i cells term + @ 0 d- carry @ m+
( hi) carry ! ( lo) swap ( res) !
-1 +loop drop ;
0 value factor
\ scan forward for cell containing non-zero
: +index ( adr -- adr index )
-1 begin 1+ dup size - while 2dup cells + @ until then ;
: Divide ( adr factor -- )
to factor 0 carry ! +index
( adr index ) size swap ?do
i cells over + ( res)
dup @ carry @ factor um/mod
( quot) rot ( res) ! ( rem) carry !
loop drop ;
\ scan backward for cell containing non-zero
: -index ( adr -- adr index )
size begin 1- dup while 2dup cells + @ until then ;
: Multiply ( adr factor -- )
to factor 0 carry ! -index
( adr index ) 0 swap do
i cells over + ( res)
dup @ factor um* carry @ m+
( hi) carry ! ( lo) swap ( res) !
-1 +loop drop ;
: Copy ( -- )
power term size cells cmove ;
\ : Zero? ( result -- f )
\ +index nip size = ;
: Zero? ( result -- f )
size cells 0 skip nip 0= ;
0 value pass
variable exp
variable sign
: Divisor ( -- n )
pass 1 = if 5 else 239 then ;
: Initialize ( -- )
power size cells erase
term size cells erase
pass 1 = if result size cells erase then
16 pass dup * / power !
power divisor Divide
1 exp ! pass 1- sign ! ;
0 value ndigit
: CalcPi ( -- )
ndigit 45800 u> if
." Warning: digits > 45808 will be in error " cr
then
2 1+ 1 do
i to pass
Initialize
begin
Copy
term exp @ Divide
sign @ dup if Subtract else Add then
0= sign ! 2 exp +!
power divisor dup * Divide
power zero?
until
loop ;
variable out
: cr cr 0 out ! ;
: # # 1 out +! ;
: Print ( -- )
result dup @ 0 .r [char] . emit cr
ndigit 0 ?do
0 over !
dup 10000 Multiply
dup @ 0 <# # # # # #> type
out @ 63 > if cr then
4 +loop
drop cr ;
: Number ( adr len -- n )
0 0 2swap >number 2drop drop ;
save [if]
: GetNumber ( -- n )
cmdtail number dup 0= abort" Usage: PI #digits" ;
[else]
: GetNumber ( -- n )
cr ." How many digits do you want? "
pad dup 20 accept number dup 0= abort" Invalid" cr ;
[then]
: main ( -- )
dos-io ( allow output redirect )
getnumber dup to ndigit
\ array size = ceil(ndigit / log10(2^16))
109 um* 525 um/mod swap ( rem) if 1+ then
( extra for accurate last digits)
2 + to size
\ create arrays
here to power size cells allot
here to term size cells allot
here to result size cells allot
calcpi
print ;
save [if]
turnkey main pi
[else]
cr .( Type MAIN to begin ) cr
[then]
\ end
Top Home Forth
![]()
Page updated: 2015-02-09