The Q6600
Benchmarks Game

pidigits Matz's Ruby #2 program

source code

# The Computer Language Benchmarks Game
# https://salsa.debian.org/benchmarksgame-team/benchmarksgame/
#
# Use libgmp-ruby_1.0 
#
# contributed by Gabriele Renzi
# modified by Pilho Kim

require 'gmp'

class PiDigitSpigot
    def initialize()
        @ZERO = GMP::Z.new(0)
        @ONE = GMP::Z.new(1)
        @THREE = GMP::Z.new(3)
        @FOUR = GMP::Z.new(4)
        @TEN = GMP::Z.new(10)
        @z = Transformation.new @ONE,@ZERO,@ZERO,@ONE
        @x = Transformation.new @ZERO,@ZERO,@ZERO,@ZERO
        @inverse = Transformation.new @ZERO,@ZERO,@ZERO,@ZERO
    end

    def next!
        @y = @z.extract(@THREE)
        if safe? @y
            @z = produce(@y)
            @y
        else
            @z = consume @x.next!()
            next!()
        end
    end

    def safe?(digit)
        digit == @z.extract(@FOUR)
    end

    def produce(i)
        @inverse.qrst(@TEN,-@TEN*i,@ZERO,@ONE).compose(@z)
    end

    def consume(a)
        @z.compose(a)
    end
end


class Transformation
    attr_reader :q, :r, :s, :t
    def initialize (q, r, s, t)
        @ZERO = GMP::Z.new(0)
        @ONE = GMP::Z.new(1)
        @TWO = GMP::Z.new(2)
        @FOUR = GMP::Z.new(4)
        @q,@r,@s,@t,@k = q,r,s,t,@ZERO
    end

    def next!()
        @q = @k = @k + @ONE
        @r = @FOUR * @k + @TWO
        @s = @ZERO
        @t = @TWO * @k + @ONE
        self
    end

    def extract(j)
        (@q * j + @r).tdiv( @s * j + @t )
    end

    def compose(a)
        self.class.new( @q * a.q,
                        @q * a.r + r * a.t,
                        @s * a.q + t * a.s,
                        @s * a.r + t * a.t
                    )
    end

    def qrst *args
        initialize *args
        self
    end

end


@zero = GMP::Z.new(0)
@one = GMP::Z.new(1)
@two = GMP::Z.new(2)
@four = GMP::Z.new(4)
@ten = GMP::Z.new(10)

WIDTH = 10
n = Integer(ARGV[0] || "27")
j = 0

digits = PiDigitSpigot.new

while n > 0
    if n >= WIDTH
        WIDTH.times {print digits.next!}
        j += WIDTH
    else
        n.times {print digits.next!}
        (WIDTH-n).times {print " "}
        j += n
    end
    puts "\t:"+j.to_s
    n -= WIDTH
end
    

notes, command-line, and program output

NOTES:
64-bit Ubuntu quad core
ruby 1.8.7 (2008-08-11 patchlevel 72) [x86_64-linux]
 
So old that I haven't been able to get rubygems to work
no backport, no gmp


Sun, 02 Jun 2019 06:18:42 GMT

COMMAND LINE:
/usr/bin/ruby pidigits.mri-2.mri 2000

PROGRAM FAILED 


PROGRAM OUTPUT:

pidigits.mri-2.mri:9:in `require': no such file to load -- gmp (LoadError)
	from pidigits.mri-2.mri:9