mp-pi.c

     
   1  //! @file mp-pi.c
   2  //! @author J. Marcel van der Veer
   3  
   4  //! @section Copyright
   5  //!
   6  //! This file is part of Algol68G - an Algol 68 compiler-interpreter.
   7  //! Copyright 2001-2026 J. Marcel van der Veer [algol68g@xs4all.nl].
   8  
   9  //! @section License
  10  //!
  11  //! This program is free software; you can redistribute it and/or modify it
  12  //! under the terms of the GNU General Public License as published by the
  13  //! Free Software Foundation; either version 3 of the License, or
  14  //! (at your option) any later version.
  15  //!
  16  //! This program is distributed in the hope that it will be useful, but
  17  //! WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
  18  //! or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
  19  //! more details. You should have received a copy of the GNU General Public
  20  //! License along with this program. If not, see [http://www.gnu.org/licenses/].
  21  
  22  //! @section Synopsis
  23  //!
  24  //! [LONG] LONG REAL value of pi by AGM.
  25  
  26  #include "a68g.h"
  27  #include "a68g-mp.h"
  28  
  29  //! @brief Return "pi" with "digs" precision, using a Borwein & Borwein AGM.
  30  
  31  MP_T *mp_pi(NODE_T *p, MP_T *api, int mod, int digs)
  32  {
  33    int gdigs = FUN_DIGITS(digs);
  34    //
  35    if (gdigs > A68G_MP(mp_pi_size))
  36    {
  37      //
  38      // No luck with the cached value, so we compute a longer "pi".
  39      // Calculate "pi" using a Borwein & Borwein AGM algorithm that doubles
  40      // the numbers of digits on each iteration.
  41      //
  42      // J. M. Borwein, P. B. Borwein. "Pi and the AGM – A Study in Analytic Number
  43      // Theory and Computational Complexity", Wiley, New York, 1987.
  44      //
  45      a68g_free(A68G_MP(mp_pi));
  46      a68g_free(A68G_MP(mp_half_pi));
  47      a68g_free(A68G_MP(mp_two_pi));
  48      a68g_free(A68G_MP(mp_sqrt_two_pi));
  49      a68g_free(A68G_MP(mp_sqrt_pi));
  50      a68g_free(A68G_MP(mp_ln_pi));
  51      a68g_free(A68G_MP(mp_180_over_pi));
  52      a68g_free(A68G_MP(mp_pi_over_180));
  53      ADDR_T pop_sp = A68G_SP;
  54      MP_T *pi_g = nil_mp(p, gdigs);
  55      MP_T *two = lit_mp(p, 2, 0, gdigs);
  56      MP_T *x_g = lit_mp(p, 2, 0, gdigs);
  57      MP_T *y_g = nil_mp(p, gdigs);
  58      MP_T *u_g = nil_mp(p, gdigs);
  59      MP_T *v_g = nil_mp(p, gdigs);
  60      (void)sqrt_mp(p, x_g, x_g, gdigs);
  61      (void)add_mp(p, pi_g, x_g, two, gdigs);
  62      (void)sqrt_mp(p, y_g, x_g, gdigs);
  63      BOOL_T iterate = A68G_TRUE;
  64      while (iterate)
  65      {
  66        // New x.
  67        (void)sqrt_mp(p, u_g, x_g, gdigs);
  68        (void)rec_mp(p, v_g, u_g, gdigs);
  69        (void)add_mp(p, u_g, u_g, v_g, gdigs);
  70        (void)half_mp(p, x_g, u_g, gdigs);
  71        // New pi.
  72        (void)plus_one_mp(p, u_g, x_g, gdigs);
  73        (void)plus_one_mp(p, v_g, y_g, gdigs);
  74        (void)div_mp(p, u_g, u_g, v_g, gdigs);
  75        (void)mul_mp(p, v_g, pi_g, u_g, gdigs);
  76        // Done yet?
  77        if (same_mp(p, v_g, pi_g, gdigs))
  78        {
  79          iterate = A68G_FALSE;
  80        }
  81        else
  82        {
  83          (void)move_mp(pi_g, v_g, gdigs);
  84          // New y.
  85          (void)sqrt_mp(p, u_g, x_g, gdigs);
  86          (void)rec_mp(p, v_g, u_g, gdigs);
  87          (void)mul_mp(p, u_g, y_g, u_g, gdigs);
  88          (void)add_mp(p, u_g, u_g, v_g, gdigs);
  89          (void)plus_one_mp(p, v_g, y_g, gdigs);
  90          (void)div_mp(p, y_g, u_g, v_g, gdigs);
  91        }
  92      }
  93      // Keep the result for future restore.
  94      (void)shorten_mp(p, api, digs, pi_g, gdigs);
  95      A68G_MP(mp_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
  96      (void)move_mp(A68G_MP(mp_pi), api, digs);
  97      A68G_MP(mp_half_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
  98      (void)half_mp(p, A68G_MP(mp_half_pi), api, digs);
  99      A68G_MP(mp_sqrt_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
 100      (void)sqrt_mp(p, A68G_MP(mp_sqrt_pi), api, digs);
 101      A68G_MP(mp_ln_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
 102      (void)ln_mp(p, A68G_MP(mp_ln_pi), api, digs);
 103      A68G_MP(mp_two_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
 104      (void)mul_mp_digit(p, A68G_MP(mp_two_pi), api, (MP_T)2, digs);
 105      A68G_MP(mp_sqrt_two_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
 106      (void)sqrt_mp(p, A68G_MP(mp_sqrt_two_pi), A68G_MP(mp_two_pi), digs);
 107      A68G_MP(mp_pi_over_180) = (MP_T *)get_heap_space(SIZE_MP(digs));
 108      (void)div_mp_digit(p, A68G_MP(mp_pi_over_180), api, 180, digs);
 109      A68G_MP(mp_180_over_pi) = (MP_T *)get_heap_space(SIZE_MP(digs));
 110      (void)rec_mp(p, A68G_MP(mp_180_over_pi), A68G_MP(mp_pi_over_180), digs);
 111      A68G_MP(mp_pi_size) = gdigs;
 112      A68G_SP = pop_sp;
 113    }
 114    switch (mod)
 115    {
 116      case MP_PI:
 117      {
 118        return move_mp(api, A68G_MP(mp_pi), digs);
 119      }
 120      case MP_HALF_PI:
 121      {
 122        return move_mp(api, A68G_MP(mp_half_pi), digs);
 123      }
 124      case MP_TWO_PI:
 125      {
 126        return move_mp(api, A68G_MP(mp_two_pi), digs);
 127      }
 128      case MP_SQRT_TWO_PI:
 129      {
 130        return move_mp(api, A68G_MP(mp_sqrt_two_pi), digs);
 131      }
 132      case MP_SQRT_PI:
 133      {
 134        return move_mp(api, A68G_MP(mp_sqrt_pi), digs);
 135      }
 136      case MP_LN_PI:
 137      {
 138        return move_mp(api, A68G_MP(mp_ln_pi), digs);
 139      }
 140      case MP_180_OVER_PI:
 141      {
 142        return move_mp(api, A68G_MP(mp_180_over_pi), digs);
 143      }
 144      case MP_PI_OVER_180:
 145      {
 146        return move_mp(api, A68G_MP(mp_pi_over_180), digs);
 147      }
 148      default:
 149      {
 150        return NaN_MP; // Should not be here.
 151      }
 152    }
 153  }
     


© 2002-2026 J.M. van der Veer (jmvdveer@xs4all.nl)