5
* Copyright (C) 2003 - 2007 Michael C. Ring
7
* Permission to use, copy, and distribute this software and its
8
* documentation for any purpose with or without fee is hereby granted,
9
* provided that the above copyright notice appear in all copies and
10
* that both that copyright notice and this permission notice appear
11
* in supporting documentation.
13
* Permission to modify the software is granted. Permission to distribute
14
* the modified code is granted. Modifications are to be distributed by
15
* using the file 'license.txt' as a template to modify the file header.
16
* 'license.txt' is available in the official MAPM distribution.
18
* This software is provided "as is" without express or implied warranty.
23
* This file contains the function to compute log(2), log(10),
24
* and 1/log(10) to the desired precision using an AGM algorithm.
29
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
32
* using the 'R' function (defined below) for 'N' decimal places :
36
* log(2) = R(1, 0.5 * 10 ) - R(1, 10 )
40
* log(10) = R(1, 0.1 * 10 ) - R(1, 10 )
46
* log(x) = R(1, 10 / x) - R(1, 10 )
49
* I found this on a web site which went into considerable detail
50
* on the history of log(2). This formula is algebraically identical
51
* to the formula specified in J. Borwein and P. Borwein's book
52
* "PI and the AGM". (reference algorithm 7.2)
55
/****************************************************************************/
57
* check if our local copy of log(2) & log(10) is precise
58
* enough for our purpose. if not, calculate them so it's
59
* as precise as desired, accurate to at least 'places'.
61
void M_check_log_places(int places)
63
M_APM tmp6, tmp7, tmp8, tmp9;
68
if (dplaces > MM_lc_log_digits)
70
MM_lc_log_digits = dplaces + 4;
72
tmp6 = M_get_stack_var();
73
tmp7 = M_get_stack_var();
74
tmp8 = M_get_stack_var();
75
tmp9 = M_get_stack_var();
77
dplaces += 6 + (int)log10((double)places);
79
m_apm_copy(tmp7, MM_One);
80
tmp7->m_apm_exponent = -places;
82
M_log_AGM_R_func(tmp8, dplaces, MM_One, tmp7);
84
m_apm_multiply(tmp6, tmp7, MM_0_5);
86
M_log_AGM_R_func(tmp9, dplaces, MM_One, tmp6);
88
m_apm_subtract(MM_lc_log2, tmp9, tmp8); /* log(2) */
90
tmp7->m_apm_exponent -= 1; /* divide by 10 */
92
M_log_AGM_R_func(tmp9, dplaces, MM_One, tmp7);
94
m_apm_subtract(MM_lc_log10, tmp9, tmp8); /* log(10) */
95
m_apm_reciprocal(MM_lc_log10R, dplaces, MM_lc_log10); /* 1 / log(10) */
100
/****************************************************************************/
103
* define a notation for a function 'R' :
108
* R (a0, b0) = ------------------------------
120
* where a, b are the classic AGM iteration :
132
* define a variable 'c' for more efficient computation :
135
* c = 0.5 * (a - b ) , c = a - b
140
/****************************************************************************/
141
void M_log_AGM_R_func(M_APM rr, int places, M_APM aa, M_APM bb)
143
M_APM tmp1, tmp2, tmp3, tmp4, tmpC2, sum, pow_2, tmpA0, tmpB0;
144
int tolerance, dplaces;
146
tmpA0 = M_get_stack_var();
147
tmpB0 = M_get_stack_var();
148
tmpC2 = M_get_stack_var();
149
tmp1 = M_get_stack_var();
150
tmp2 = M_get_stack_var();
151
tmp3 = M_get_stack_var();
152
tmp4 = M_get_stack_var();
153
sum = M_get_stack_var();
154
pow_2 = M_get_stack_var();
156
tolerance = places + 8;
157
dplaces = places + 16;
159
m_apm_copy(tmpA0, aa);
160
m_apm_copy(tmpB0, bb);
161
m_apm_copy(pow_2, MM_0_5);
163
m_apm_multiply(tmp1, aa, aa); /* 0.5 * [ a ^ 2 - b ^ 2 ] */
164
m_apm_multiply(tmp2, bb, bb);
165
m_apm_subtract(tmp3, tmp1, tmp2);
166
m_apm_multiply(sum, MM_0_5, tmp3);
170
m_apm_subtract(tmp1, tmpA0, tmpB0); /* C n+1 = 0.5 * [ An - Bn ] */
171
m_apm_multiply(tmp4, MM_0_5, tmp1); /* C n+1 */
172
m_apm_multiply(tmpC2, tmp4, tmp4); /* C n+1 ^ 2 */
176
m_apm_add(tmp1, tmpA0, tmpB0);
177
m_apm_multiply(tmp3, MM_0_5, tmp1);
179
m_apm_multiply(tmp2, tmpA0, tmpB0);
180
m_apm_sqrt(tmpB0, dplaces, tmp2);
182
m_apm_round(tmpA0, dplaces, tmp3);
186
m_apm_multiply(tmp2, MM_Two, pow_2);
187
m_apm_copy(pow_2, tmp2);
189
m_apm_multiply(tmp1, tmpC2, pow_2);
190
m_apm_add(tmp3, sum, tmp1);
192
if ((tmp1->m_apm_sign == 0) ||
193
((-2 * tmp1->m_apm_exponent) > tolerance))
196
m_apm_round(sum, dplaces, tmp3);
199
m_apm_subtract(tmp4, MM_One, tmp3);
200
m_apm_reciprocal(rr, places, tmp4);
204
/****************************************************************************/