-
Notifications
You must be signed in to change notification settings - Fork 0
/
Pi Day.rb
126 lines (114 loc) · 2.5 KB
/
Pi Day.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#!/usr/bin/env ruby
# encoding: UTF-8
# warn_indent: true
#
# !!! enforce line endings LF only !!!
# shell may fail to correctly recognize interpreter if CR precedes or replaces LF
#
#---------#---------#---------#---------#---------#---------#---------#---------#---------#---------#
#
$VERBOSE = true
require 'io/console'
def termwidth
if !IO or !IO.console or !IO.console.winsize
return 80 # default
else
return IO.console.winsize[1]
end
end
## Derived from https://possiblywrong.wordpress.com/2017/09/30/digits-of-pi-and-python-generators/
class Continued_Fraction_Spigot
def initialize( a, b, base=10 )
@a = a
@b = b
@base = base
# Generate digits of continued fraction a(0)+b(1)/(a(1)+b(2)/(...).
@p0 = a.call(0)
@q0 = 1
@p1 = a.call(1) * a.call(0) + b.call(1)
@q1 = a.call(1)
@k = 1
@dot = false
#puts "step 1: #{p0} + #{b.call(1)} /( #{q1} + ..."
end
def next( count=1 )
out = ""
count.times do
out += self.step
end
out
end
def step
out = nil
# puts "k = #{@k}\tdot #{@dot}"
if !@dot and 3 == @k
# puts "DOT"
out = "."
@dot = true
end
while nil == out do
d0, r0 = @p0.divmod(@q0)
d1, r1 = @p1.divmod(@q1)
# puts "k = #{@k}\td0 = #{d0}\td1 = #{d1}\tr0 = #{r0}\tr1 = #{r1}\tp0 = #{@p0}\tp1 = #{@p1}\tq0 = #{@q0}\tq1 = #{@q1}"
if d0 == d1
out = d1.to_s
# puts "next digit = #{out}"
# print out
@p0 = @base * r0
@p1 = @base * r1
else
@k = @k + 1
x = @a.call(@k)
y = @b.call(@k)
# puts "step #{@k}: ... + #{y} /( #{x} + ..."
# p0 = p1
# q0 = q1
# p1 = x * p1 + y * p0
# q1 = x * q1 + y * q0
@p0, @q0, @p1, @q1 = @p1, @q1, x * @p1 + y * @p0, x * @q1 + y * @q0 # single statement prevents use-after-change errors
end
end
# puts "next digit = #{out}"
out
end
end
class Pi_Spigot < Continued_Fraction_Spigot
def initialize( base=10 )
super(
lambda { |k| k == 0 ? 0 : 2 * k - 1 },
lambda { |k| k == 1 ? 4 : (k - 1)**2 },
base
)
end
end
linecount = ARGV.length > 0 ? ARGV[0].to_i : 3
perline = ARGV.length > 1 ? ARGV[1].to_i : termwidth
#puts "#{linecount} lines of #{perline} digits"
if linecount <= 0 or perline <= 0
puts "BUT PI MUST BE NONZERO!"
exit 1
end
pi = Pi_Spigot.new
moar = true
while moar do
linecount.times do
puts pi.next( perline )
end
puts
while true do
print "MOAR PI? (Y/N) "
case STDIN.gets.strip[0].downcase
when "y"
puts
break
when "n"
moar = false
break
else
# ask again
end
end
end
puts
puts "MMM, FULL WITH PI!"
puts