172878Skris/*
272878SkrisRedistribution and use in source and binary forms, with or without
3100772Sjhbmodification, are permitted provided that the following conditions are met:
4100772Sjhb
5100772Sjhb    * Redistributions of source code must retain the above copyright
672878Skris    notice, this list of conditions and the following disclaimer.
7101232Sru
8136606Sobrien    * Redistributions in binary form must reproduce the above copyright
9100773Sjhb    notice, this list of conditions and the following disclaimer in the
10113374Sobrien    documentation and/or other materials provided with the distribution.
11126657Sbde
12115175Speter    * Neither the name of "The Computer Language Benchmarks Game" nor the
13100773Sjhb    name of "The Computer Language Shootout Benchmarks" nor the names of
14103560Sjhb    its contributors may be used to endorse or promote products derived
15176776Sraj    from this software without specific prior written permission.
16176776Sraj
17100773SjhbTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18129217ScognetAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19129217ScognetIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20100773SjhbARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21100772SjhbLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2272878SkrisCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2372878SkrisSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2472878SkrisINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2572878SkrisCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26100773SjhbARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27166071SdesPOSSIBILITY OF SUCH DAMAGE.
28166071Sdes*/
29166071Sdes
30166071Sdes/* The Computer Language Benchmarks Game
31136607Sobrien * http://shootout.alioth.debian.org/
32136606Sobrien *
33136606Sobrien * contributed by The Go Authors.
34136606Sobrien * based on pidigits.c (by Paolo Bonzini & Sean Bartlett,
35136606Sobrien *                      modified by Michael Mellor)
36136606Sobrien */
37136606Sobrien
38136606Sobrienpackage main
39136606Sobrien
40136606Sobrienimport (
41136606Sobrien	"flag"
42136606Sobrien	"fmt"
43136606Sobrien	"math/big"
44136606Sobrien)
45136606Sobrien
46136606Sobrienvar n = flag.Int("n", 27, "number of digits")
47136606Sobrienvar silent = flag.Bool("s", false, "don't print result")
48136606Sobrien
49136607Sobrienvar (
50136607Sobrien	tmp1  = big.NewInt(0)
51133525Sobrien	tmp2  = big.NewInt(0)
52103045Smux	tmp3  = big.NewInt(0)
53103045Smux	y2    = big.NewInt(0)
54100773Sjhb	bigk  = big.NewInt(0)
55136607Sobrien	numer = big.NewInt(1)
56166072Sdes	accum = big.NewInt(0)
57136607Sobrien	denom = big.NewInt(1)
58136607Sobrien	ten   = big.NewInt(10)
5972878Skris)
6072878Skris
61136606Sobrienfunc extract_digit() int64 {
6296421Sobrien	if numer.Cmp(accum) > 0 {
6372878Skris		return -1
6496421Sobrien	}
65160536Simp
66127258Smarcel	// Compute (numer * 3 + accum) / denom
67127258Smarcel	tmp1.Lsh(numer, 1)
6896421Sobrien	tmp1.Add(tmp1, numer)
69127258Smarcel	tmp1.Add(tmp1, accum)
7072878Skris	tmp1.DivMod(tmp1, denom, tmp2)
7172878Skris
72127888Sdfr	// Now, if (numer * 4 + accum) % denom...
73133000Sobrien	tmp2.Add(tmp2, numer)
74136606Sobrien
75136606Sobrien	// ... is normalized, then the two divisions have the same result.
76136606Sobrien	if tmp2.Cmp(denom) >= 0 {
77136606Sobrien		return -1
78136606Sobrien	}
79136606Sobrien
80127888Sdfr	return tmp1.Int64()
81127888Sdfr}
82126938Strhodes
83126890Strhodesfunc next_term(k int64) {
84126890Strhodes	y2.SetInt64(k*2 + 1)
85126890Strhodes	bigk.SetInt64(k)
86112768Sobrien
87126890Strhodes	tmp1.Lsh(numer, 1)
8872878Skris	accum.Add(accum, tmp1)
89126890Strhodes	accum.Mul(accum, y2)
90136606Sobrien	numer.Mul(numer, bigk)
91126890Strhodes	denom.Mul(denom, y2)
92136606Sobrien}
93136606Sobrien
94126890Strhodesfunc eliminate_digit(d int64) {
95136606Sobrien	tmp3.SetInt64(d)
96126890Strhodes	accum.Sub(accum, tmp3.Mul(denom, tmp3))
97136606Sobrien	accum.Mul(accum, ten)
98126890Strhodes	numer.Mul(numer, ten)
99136606Sobrien}
100126890Strhodes
101136606Sobrienfunc printf(s string, arg ...interface{}) {
102126890Strhodes	if !*silent {
103136606Sobrien		fmt.Printf(s, arg...)
104136607Sobrien	}
105136607Sobrien}
106135678Scognet
107136606Sobrienfunc main() {
108172706Scognet	flag.Parse()
109172706Scognet
110172706Scognet	var m int // 0 <= m < 10
111136606Sobrien	for i, k := 0, int64(0); ; {
112136606Sobrien		d := int64(-1)
113135678Scognet		for d < 0 {
114176776Sraj			k++
115176776Sraj			next_term(k)
116176776Sraj			d = extract_digit()
117176776Sraj		}
118176776Sraj
11972878Skris		printf("%c", d+'0')
12072878Skris
12172878Skris		i++
12272878Skris		m = i % 10
12372878Skris		if m == 0 {
12472878Skris			printf("\t:%d\n", i)
125126657Sbde		}
126136607Sobrien		if i >= *n {
127136607Sobrien			break
128136607Sobrien		}
129125254Sbde		eliminate_digit(d)
130136606Sobrien	}
131126657Sbde
132112768Sobrien	if m > 0 {
133126657Sbde		printf("%s\t:%d\n", "          "[m:10], *n)
134103045Smux	}
135103562Sjhb}
13674069Ssobomax