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 iterative function to compute the LOG
24
* This is an internal function to the library and is not intended
25
* to be called directly by the user.
30
#include "pgscript/utilities/mapm-lib/m_apm_lc.h"
32
/****************************************************************************/
35
* compute rr = log(nn)
37
* input is assumed to not exceed the exponent range of a normal
38
* 'C' double ( |exponent| must be < 308)
41
/****************************************************************************/
42
void M_log_solve_cubic(M_APM rr, int places, M_APM nn)
44
M_APM tmp0, tmp1, tmp2, tmp3, guess;
45
int ii, maxp, tolerance, local_precision;
47
guess = M_get_stack_var();
48
tmp0 = M_get_stack_var();
49
tmp1 = M_get_stack_var();
50
tmp2 = M_get_stack_var();
51
tmp3 = M_get_stack_var();
53
M_get_log_guess(guess, nn);
55
tolerance = -(places + 4);
59
/* Use the following iteration to solve for log :
62
X = X - 2 * ------------
66
this is a cubically convergent algorithm
67
(each iteration yields 3X more digits)
74
m_apm_exp(tmp1, local_precision, guess);
76
m_apm_subtract(tmp3, tmp1, nn);
77
m_apm_add(tmp2, tmp1, nn);
79
m_apm_divide(tmp1, local_precision, tmp3, tmp2);
80
m_apm_multiply(tmp0, MM_Two, tmp1);
81
m_apm_subtract(tmp3, guess, tmp0);
85
if (((3 * tmp0->m_apm_exponent) < tolerance) || (tmp0->m_apm_sign == 0))
89
m_apm_round(guess, local_precision, tmp3);
93
if (local_precision > maxp)
94
local_precision = maxp;
99
m_apm_round(rr, places, tmp3);
102
/****************************************************************************/
107
* solve with cubically convergent algorithm above
111
* let 'X' be 'close' to the solution (we use ~110 decimal places)
113
* let Y = N * exp(-X) - 1
117
* log(N) = X + log(1 + Y)
119
* since 'Y' will be small, we can use the efficient log_near_1 algorithm.
122
void M_log_basic_iteration(M_APM rr, int places, M_APM nn)
124
M_APM tmp0, tmp1, tmp2, tmpX;
128
M_log_solve_cubic(rr, places, nn);
132
tmp0 = M_get_stack_var();
133
tmp1 = M_get_stack_var();
134
tmp2 = M_get_stack_var();
135
tmpX = M_get_stack_var();
137
M_log_solve_cubic(tmpX, 110, nn);
139
m_apm_negate(tmp0, tmpX);
140
m_apm_exp(tmp1, (places + 8), tmp0);
141
m_apm_multiply(tmp2, tmp1, nn);
142
m_apm_subtract(tmp1, tmp2, MM_One);
144
M_log_near_1(tmp0, (places - 104), tmp1);
146
m_apm_add(tmp1, tmpX, tmp0);
147
m_apm_round(rr, places, tmp1);
152
/****************************************************************************/