• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020-2024 Stefan Krah. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  *
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  */
26 
27 
28 #include <cassert>
29 #include <climits>
30 
31 #include <iostream>
32 #include <stdexcept>
33 #include <string>
34 
35 #include "decimal.hh"
36 
37 
38 using decimal::Decimal;
39 using decimal::context;
40 
41 
42 /* The algorithm is not optimized for bignum arithmetic */
43 Decimal
pi(int prec)44 pi(int prec)
45 {
46     assert(1 <= prec && prec <= INT_MAX-2);
47     context.prec(prec + 2);
48 
49     Decimal lasts = 0;
50     Decimal t = 3;
51     Decimal s = 3;
52     Decimal n = 1;
53     Decimal na = 0;
54     Decimal d = 0;
55     Decimal da = 24;
56 
57     while (s != lasts) {
58         lasts = s;
59         n += na;
60         na += 8;
61         d += da;
62         da += 32;
63         t = (t * n) / d;
64         s += t;
65     }
66 
67     context.prec(prec);
68     return +s;
69 }
70 
71 void
err_exit(const std::string & msg)72 err_exit(const std::string& msg)
73 {
74     std::cerr << msg << std::endl;
75     std::exit(1);
76 }
77 
78 
79 int
main(int argc,char * argv[])80 main(int argc, char *argv[])
81 {
82     size_t pos = 0;
83     int prec = 0;
84 
85     if (argc != 2) {
86         err_exit("usage: ./pi prec");
87     }
88     std::string s = argv[1];
89 
90     try {
91         prec = std::stoi(s, &pos);
92     } catch (const std::invalid_argument&) {
93         err_exit("not a number");
94     } catch (const std::out_of_range &) {
95         err_exit("out of range");
96     }
97 
98     if (pos < s.size()) {
99         err_exit("trailing characters");
100     }
101     if (prec <= 0 || prec > 999999) {
102         err_exit("prec must be in [1, 999999]");
103     }
104 
105     std::cout << pi(prec) << std::endl;
106 
107     return 0;
108 }
109