pi.c
上传用户:lyxiangda
上传日期:2007-01-12
资源大小:3042k
文件大小:5k
源码类别:

CA认证

开发平台:

WINDOWS

  1. /*
  2.  * pi.c
  3.  *
  4.  * Compute pi to an arbitrary number of digits.  Uses Machin's formula,
  5.  * like everyone else on the planet:
  6.  * 
  7.  *    pi = 16 * arctan(1/5) - 4 * arctan(1/239)
  8.  *
  9.  * This is pretty effective for up to a few thousand digits, but it
  10.  * gets pretty slow after that.
  11.  *
  12.  * The contents of this file are subject to the Mozilla Public
  13.  * License Version 1.1 (the "License"); you may not use this file
  14.  * except in compliance with the License. You may obtain a copy of
  15.  * the License at http://www.mozilla.org/MPL/
  16.  *
  17.  * Software distributed under the License is distributed on an "AS
  18.  * IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or
  19.  * implied. See the License for the specific language governing
  20.  * rights and limitations under the License.
  21.  *
  22.  * The Original Code is the MPI Arbitrary Precision Integer Arithmetic
  23.  * library.
  24.  *
  25.  * The Initial Developer of the Original Code is Michael J. Fromberger.
  26.  * Portions created by Michael J. Fromberger are 
  27.  * Copyright (C) 1999, 2000 Michael J. Fromberger. 
  28.  * All Rights Reserved.
  29.  *
  30.  * Contributor(s):
  31.  *
  32.  * Alternatively, the contents of this file may be used under the
  33.  * terms of the GNU General Public License Version 2 or later (the
  34.  * "GPL"), in which case the provisions of the GPL are applicable
  35.  * instead of those above.  If you wish to allow use of your
  36.  * version of this file only under the terms of the GPL and not to
  37.  * allow others to use your version of this file under the MPL,
  38.  * indicate your decision by deleting the provisions above and
  39.  * replace them with the notice and other provisions required by
  40.  * the GPL.  If you do not delete the provisions above, a recipient
  41.  * may use your version of this file under either the MPL or the GPL.
  42.  *
  43.  * $Id: pi.c,v 1.1 2000/07/14 00:45:00 nelsonb%netscape.com Exp $ 
  44.  */
  45. #include <stdio.h>
  46. #include <stdlib.h>
  47. #include <string.h>
  48. #include <limits.h>
  49. #include <time.h>
  50. #include "mpi.h"
  51. mp_err arctan(mp_digit mul, mp_digit x, mp_digit prec, mp_int *sum);
  52. int main(int argc, char *argv[])
  53. {
  54.   mp_err       res;
  55.   mp_digit     ndigits;
  56.   mp_int       sum1, sum2;
  57.   clock_t      start, stop;
  58.   int          out = 0;
  59.   /* Make the user specify precision on the command line */
  60.   if(argc < 2) {
  61.     fprintf(stderr, "Usage: %s <num-digits>n", argv[0]);
  62.     return 1;
  63.   }
  64.   if((ndigits = abs(atoi(argv[1]))) == 0) {
  65.     fprintf(stderr, "%s: you must request at least 1 digitn", argv[0]);
  66.     return 1;
  67.   }
  68.   start = clock();
  69.   mp_init(&sum1); mp_init(&sum2);
  70.   /* sum1 = 16 * arctan(1/5)  */
  71.   if((res = arctan(16, 5, ndigits, &sum1)) != MP_OKAY) {
  72.     fprintf(stderr, "%s: arctan: %sn", argv[0], mp_strerror(res));
  73.     out = 1; goto CLEANUP;
  74.   }
  75.   /* sum2 = 4 * arctan(1/239) */
  76.   if((res = arctan(4, 239, ndigits, &sum2)) != MP_OKAY) {
  77.     fprintf(stderr, "%s: arctan: %sn", argv[0], mp_strerror(res));
  78.     out = 1; goto CLEANUP;
  79.   }
  80.   /* pi = sum1 - sum2         */
  81.   if((res = mp_sub(&sum1, &sum2, &sum1)) != MP_OKAY) {
  82.     fprintf(stderr, "%s: mp_sub: %sn", argv[0], mp_strerror(res));
  83.     out = 1; goto CLEANUP;
  84.   }
  85.   stop = clock();
  86.   /* Write the output in decimal */
  87.   {
  88.     char  *buf = malloc(mp_radix_size(&sum1, 10));
  89.     if(buf == NULL) {
  90.       fprintf(stderr, "%s: out of memoryn", argv[0]);
  91.       out = 1; goto CLEANUP;
  92.     }
  93.     mp_todecimal(&sum1, buf);
  94.     printf("%sn", buf);
  95.     free(buf);
  96.   }
  97.   fprintf(stderr, "Computation took %.2f sec.n", 
  98.   (double)(stop - start) / CLOCKS_PER_SEC);
  99.  CLEANUP:
  100.   mp_clear(&sum1);
  101.   mp_clear(&sum2);
  102.   return out;
  103. }
  104. /* Compute sum := mul * arctan(1/x), to 'prec' digits of precision */
  105. mp_err arctan(mp_digit mul, mp_digit x, mp_digit prec, mp_int *sum)
  106. {
  107.   mp_int   t, v;
  108.   mp_digit q = 1, rd;
  109.   mp_err   res;
  110.   int      sign = 1;
  111.   prec += 3;  /* push inaccuracies off the end */
  112.   mp_init(&t); mp_set(&t, 10);
  113.   mp_init(&v); 
  114.   if((res = mp_expt_d(&t, prec, &t)) != MP_OKAY ||  /* get 10^prec    */
  115.      (res = mp_mul_d(&t, mul, &t)) != MP_OKAY ||    /* ... times mul  */
  116.      (res = mp_mul_d(&t, x, &t)) != MP_OKAY)        /* ... times x    */
  117.     goto CLEANUP;
  118.   /*
  119.     The extra multiplication by x in the above takes care of what
  120.     would otherwise have to be a special case for 1 / x^1 during the
  121.     first loop iteration.  A little sneaky, but effective.
  122.     We compute arctan(1/x) by the formula:
  123.          1     1       1       1
  124.  - - ----- + ----- - ----- + ...
  125.  x   3 x^3   5 x^5   7 x^7
  126.     We multiply through by 'mul' beforehand, which gives us a couple
  127.     more iterations and more precision
  128.    */
  129.   x *= x; /* works as long as x < sqrt(RADIX), which it is here */
  130.   mp_zero(sum);
  131.   do {
  132.     if((res = mp_div_d(&t, x, &t, &rd)) != MP_OKAY)
  133.       goto CLEANUP;
  134.     if(sign < 0 && rd != 0)
  135.       mp_add_d(&t, 1, &t);
  136.     if((res = mp_div_d(&t, q, &v, &rd)) != MP_OKAY)
  137.       goto CLEANUP;
  138.     if(sign < 0 && rd != 0)
  139.       mp_add_d(&v, 1, &v);
  140.     if(sign > 0)
  141.       res = mp_add(sum, &v, sum);
  142.     else
  143.       res = mp_sub(sum, &v, sum);
  144.     if(res != MP_OKAY)
  145.       goto CLEANUP;
  146.     sign *= -1;
  147.     q += 2;
  148.   } while(mp_cmp_z(&t) != 0);
  149.   /* Chop off inaccurate low-order digits */
  150.   mp_div_d(sum, 1000, sum, NULL);
  151.  CLEANUP:
  152.   mp_clear(&v);
  153.   mp_clear(&t);
  154.   return res;
  155. }
  156. /*------------------------------------------------------------------------*/
  157. /* HERE THERE BE DRAGONS                                                  */