xref: /llvm-project/polly/lib/External/isl/imath/examples/pi.c (revision 658eb9e14264d48888ade0e3daf0b648f76c3f0e)
1*658eb9e1SMichael Kruse /*
2*658eb9e1SMichael Kruse   Name:     pi.c
3*658eb9e1SMichael Kruse   Purpose:  Computes digits of the physical constant pi.
4*658eb9e1SMichael Kruse   Author:   M. J. Fromberger
5*658eb9e1SMichael Kruse 
6*658eb9e1SMichael Kruse   Copyright (C) 2002-2008 Michael J. Fromberger, All Rights Reserved.
7*658eb9e1SMichael Kruse 
8*658eb9e1SMichael Kruse   Notes:
9*658eb9e1SMichael Kruse   Uses Machin's formula, which should be suitable for a few thousand digits.
10*658eb9e1SMichael Kruse 
11*658eb9e1SMichael Kruse   Permission is hereby granted, free of charge, to any person obtaining a copy
12*658eb9e1SMichael Kruse   of this software and associated documentation files (the "Software"), to deal
13*658eb9e1SMichael Kruse   in the Software without restriction, including without limitation the rights
14*658eb9e1SMichael Kruse   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15*658eb9e1SMichael Kruse   copies of the Software, and to permit persons to whom the Software is
16*658eb9e1SMichael Kruse   furnished to do so, subject to the following conditions:
17*658eb9e1SMichael Kruse 
18*658eb9e1SMichael Kruse   The above copyright notice and this permission notice shall be included in
19*658eb9e1SMichael Kruse   all copies or substantial portions of the Software.
20*658eb9e1SMichael Kruse 
21*658eb9e1SMichael Kruse   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22*658eb9e1SMichael Kruse   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23*658eb9e1SMichael Kruse   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
24*658eb9e1SMichael Kruse   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25*658eb9e1SMichael Kruse   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26*658eb9e1SMichael Kruse   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
27*658eb9e1SMichael Kruse   SOFTWARE.
28*658eb9e1SMichael Kruse  */
29*658eb9e1SMichael Kruse 
30*658eb9e1SMichael Kruse #include <stdio.h>
31*658eb9e1SMichael Kruse #include <stdlib.h>
32*658eb9e1SMichael Kruse #include <string.h>
33*658eb9e1SMichael Kruse #include <time.h>
34*658eb9e1SMichael Kruse 
35*658eb9e1SMichael Kruse #include "imath.h"
36*658eb9e1SMichael Kruse 
37*658eb9e1SMichael Kruse int g_radix = 10; /* use this radix for output */
38*658eb9e1SMichael Kruse 
39*658eb9e1SMichael Kruse mp_result arctan(mp_small radix, mp_small mul, mp_small x, mp_small prec,
40*658eb9e1SMichael Kruse                  mp_int sum);
41*658eb9e1SMichael Kruse 
42*658eb9e1SMichael Kruse char g_buf[4096];
43*658eb9e1SMichael Kruse 
main(int argc,char * argv[])44*658eb9e1SMichael Kruse int main(int argc, char *argv[]) {
45*658eb9e1SMichael Kruse   mp_result res;
46*658eb9e1SMichael Kruse   mpz_t sum1, sum2;
47*658eb9e1SMichael Kruse   int ndigits, out = 0;
48*658eb9e1SMichael Kruse   clock_t start, end;
49*658eb9e1SMichael Kruse 
50*658eb9e1SMichael Kruse   if (argc < 2) {
51*658eb9e1SMichael Kruse     fprintf(stderr, "Usage: %s <num-digits> [<radix>]\n", argv[0]);
52*658eb9e1SMichael Kruse     return 1;
53*658eb9e1SMichael Kruse   }
54*658eb9e1SMichael Kruse 
55*658eb9e1SMichael Kruse   if ((ndigits = abs(atoi(argv[1]))) == 0) {
56*658eb9e1SMichael Kruse     fprintf(stderr, "%s: you must request at least 1 digit\n", argv[0]);
57*658eb9e1SMichael Kruse     return 1;
58*658eb9e1SMichael Kruse   } else if ((mp_word)ndigits > MP_DIGIT_MAX) {
59*658eb9e1SMichael Kruse     fprintf(stderr, "%s: you may request at most %u digits\n", argv[0],
60*658eb9e1SMichael Kruse             (unsigned int)MP_DIGIT_MAX);
61*658eb9e1SMichael Kruse     return 1;
62*658eb9e1SMichael Kruse   }
63*658eb9e1SMichael Kruse 
64*658eb9e1SMichael Kruse   if (argc > 2) {
65*658eb9e1SMichael Kruse     int radix = atoi(argv[2]);
66*658eb9e1SMichael Kruse 
67*658eb9e1SMichael Kruse     if (radix < MP_MIN_RADIX || radix > MP_MAX_RADIX) {
68*658eb9e1SMichael Kruse       fprintf(stderr, "%s: you may only specify a radix between %d and %d\n",
69*658eb9e1SMichael Kruse               argv[0], MP_MIN_RADIX, MP_MAX_RADIX);
70*658eb9e1SMichael Kruse       return 1;
71*658eb9e1SMichael Kruse     }
72*658eb9e1SMichael Kruse     g_radix = radix;
73*658eb9e1SMichael Kruse   }
74*658eb9e1SMichael Kruse 
75*658eb9e1SMichael Kruse   mp_int_init(&sum1);
76*658eb9e1SMichael Kruse   mp_int_init(&sum2);
77*658eb9e1SMichael Kruse   start = clock();
78*658eb9e1SMichael Kruse 
79*658eb9e1SMichael Kruse   /* sum1 = 16 * arctan(1/5) */
80*658eb9e1SMichael Kruse   if ((res = arctan(g_radix, 16, 5, ndigits, &sum1)) != MP_OK) {
81*658eb9e1SMichael Kruse     fprintf(stderr, "%s: error computing arctan: %d\n", argv[0], res);
82*658eb9e1SMichael Kruse     out = 1;
83*658eb9e1SMichael Kruse     goto CLEANUP;
84*658eb9e1SMichael Kruse   }
85*658eb9e1SMichael Kruse 
86*658eb9e1SMichael Kruse   /* sum2 = 4 * arctan(1/239) */
87*658eb9e1SMichael Kruse   if ((res = arctan(g_radix, 4, 239, ndigits, &sum2)) != MP_OK) {
88*658eb9e1SMichael Kruse     fprintf(stderr, "%s: error computing arctan: %d\n", argv[0], res);
89*658eb9e1SMichael Kruse     out = 1;
90*658eb9e1SMichael Kruse     goto CLEANUP;
91*658eb9e1SMichael Kruse   }
92*658eb9e1SMichael Kruse 
93*658eb9e1SMichael Kruse   /* pi = sum1 - sum2 */
94*658eb9e1SMichael Kruse   if ((res = mp_int_sub(&sum1, &sum2, &sum1)) != MP_OK) {
95*658eb9e1SMichael Kruse     fprintf(stderr, "%s: error computing pi: %d\n", argv[0], res);
96*658eb9e1SMichael Kruse     out = 1;
97*658eb9e1SMichael Kruse     goto CLEANUP;
98*658eb9e1SMichael Kruse   }
99*658eb9e1SMichael Kruse   end = clock();
100*658eb9e1SMichael Kruse 
101*658eb9e1SMichael Kruse   mp_int_to_string(&sum1, g_radix, g_buf, sizeof(g_buf));
102*658eb9e1SMichael Kruse   printf("%c.%s\n", g_buf[0], g_buf + 1);
103*658eb9e1SMichael Kruse 
104*658eb9e1SMichael Kruse   fprintf(stderr, "Computation took %.2f sec.\n",
105*658eb9e1SMichael Kruse           (double)(end - start) / CLOCKS_PER_SEC);
106*658eb9e1SMichael Kruse 
107*658eb9e1SMichael Kruse CLEANUP:
108*658eb9e1SMichael Kruse   mp_int_clear(&sum1);
109*658eb9e1SMichael Kruse   mp_int_clear(&sum2);
110*658eb9e1SMichael Kruse 
111*658eb9e1SMichael Kruse   return out;
112*658eb9e1SMichael Kruse }
113*658eb9e1SMichael Kruse 
114*658eb9e1SMichael Kruse /*
115*658eb9e1SMichael Kruse   Compute mul * atan(1/x) to prec digits of precision, and store the
116*658eb9e1SMichael Kruse   result in sum.
117*658eb9e1SMichael Kruse 
118*658eb9e1SMichael Kruse   Computes atan(1/x) using the formula:
119*658eb9e1SMichael Kruse 
120*658eb9e1SMichael Kruse                1     1      1      1
121*658eb9e1SMichael Kruse   atan(1/x) = --- - ---- + ---- - ---- + ...
122*658eb9e1SMichael Kruse                x    3x^3   5x^5   7x^7
123*658eb9e1SMichael Kruse 
124*658eb9e1SMichael Kruse  */
arctan(mp_small radix,mp_small mul,mp_small x,mp_small prec,mp_int sum)125*658eb9e1SMichael Kruse mp_result arctan(mp_small radix, mp_small mul, mp_small x, mp_small prec,
126*658eb9e1SMichael Kruse                  mp_int sum) {
127*658eb9e1SMichael Kruse   mpz_t t, v;
128*658eb9e1SMichael Kruse   mp_result res;
129*658eb9e1SMichael Kruse   mp_small rem, sign = 1, coeff = 1;
130*658eb9e1SMichael Kruse 
131*658eb9e1SMichael Kruse   mp_int_init(&t);
132*658eb9e1SMichael Kruse   mp_int_init(&v);
133*658eb9e1SMichael Kruse   ++prec;
134*658eb9e1SMichael Kruse 
135*658eb9e1SMichael Kruse   /* Compute mul * radix^prec * x
136*658eb9e1SMichael Kruse      The initial multiplication by x saves a special case in the loop for
137*658eb9e1SMichael Kruse      the first term of the series.
138*658eb9e1SMichael Kruse    */
139*658eb9e1SMichael Kruse   if ((res = mp_int_expt_value(radix, prec, &t)) != MP_OK ||
140*658eb9e1SMichael Kruse       (res = mp_int_mul_value(&t, mul, &t)) != MP_OK ||
141*658eb9e1SMichael Kruse       (res = mp_int_mul_value(&t, x, &t)) != MP_OK)
142*658eb9e1SMichael Kruse     goto CLEANUP;
143*658eb9e1SMichael Kruse 
144*658eb9e1SMichael Kruse   x *= x; /* assumes x <= sqrt(MP_SMALL_MAX) */
145*658eb9e1SMichael Kruse   mp_int_zero(sum);
146*658eb9e1SMichael Kruse 
147*658eb9e1SMichael Kruse   do {
148*658eb9e1SMichael Kruse     if ((res = mp_int_div_value(&t, x, &t, &rem)) != MP_OK) goto CLEANUP;
149*658eb9e1SMichael Kruse 
150*658eb9e1SMichael Kruse     if ((res = mp_int_div_value(&t, coeff, &v, &rem)) != MP_OK) goto CLEANUP;
151*658eb9e1SMichael Kruse 
152*658eb9e1SMichael Kruse     /* Add or subtract the result depending on the current sign (1 = add) */
153*658eb9e1SMichael Kruse     if (sign > 0)
154*658eb9e1SMichael Kruse       res = mp_int_add(sum, &v, sum);
155*658eb9e1SMichael Kruse     else
156*658eb9e1SMichael Kruse       res = mp_int_sub(sum, &v, sum);
157*658eb9e1SMichael Kruse 
158*658eb9e1SMichael Kruse     if (res != MP_OK) goto CLEANUP;
159*658eb9e1SMichael Kruse     sign = -sign;
160*658eb9e1SMichael Kruse     coeff += 2;
161*658eb9e1SMichael Kruse 
162*658eb9e1SMichael Kruse   } while (mp_int_compare_zero(&t) != 0);
163*658eb9e1SMichael Kruse 
164*658eb9e1SMichael Kruse   res = mp_int_div_value(sum, radix, sum, NULL);
165*658eb9e1SMichael Kruse 
166*658eb9e1SMichael Kruse CLEANUP:
167*658eb9e1SMichael Kruse   mp_int_clear(&v);
168*658eb9e1SMichael Kruse   mp_int_clear(&t);
169*658eb9e1SMichael Kruse 
170*658eb9e1SMichael Kruse   return res;
171*658eb9e1SMichael Kruse }
172*658eb9e1SMichael Kruse 
173*658eb9e1SMichael Kruse /* Here there be dragons */
174