1*59d799daSIngo Weinhold
2*59d799daSIngo Weinhold /*
3*59d799daSIngo Weinhold * M_APM - mapmasn0.c
4*59d799daSIngo Weinhold *
5*59d799daSIngo Weinhold * Copyright (C) 2000 - 2007 Michael C. Ring
6*59d799daSIngo Weinhold *
7*59d799daSIngo Weinhold * Permission to use, copy, and distribute this software and its
8*59d799daSIngo Weinhold * documentation for any purpose with or without fee is hereby granted,
9*59d799daSIngo Weinhold * provided that the above copyright notice appear in all copies and
10*59d799daSIngo Weinhold * that both that copyright notice and this permission notice appear
11*59d799daSIngo Weinhold * in supporting documentation.
12*59d799daSIngo Weinhold *
13*59d799daSIngo Weinhold * Permission to modify the software is granted. Permission to distribute
14*59d799daSIngo Weinhold * the modified code is granted. Modifications are to be distributed by
15*59d799daSIngo Weinhold * using the file 'license.txt' as a template to modify the file header.
16*59d799daSIngo Weinhold * 'license.txt' is available in the official MAPM distribution.
17*59d799daSIngo Weinhold *
18*59d799daSIngo Weinhold * This software is provided "as is" without express or implied warranty.
19*59d799daSIngo Weinhold */
20*59d799daSIngo Weinhold
21*59d799daSIngo Weinhold /*
22*59d799daSIngo Weinhold * $Id: mapmasn0.c,v 1.8 2007/12/03 01:49:49 mike Exp $
23*59d799daSIngo Weinhold *
24*59d799daSIngo Weinhold * This file contains the 'ARC' family of functions; ARC-SIN,
25*59d799daSIngo Weinhold * ARC-COS, ARC-TAN when the input arg is very close to 0 (zero).
26*59d799daSIngo Weinhold *
27*59d799daSIngo Weinhold * $Log: mapmasn0.c,v $
28*59d799daSIngo Weinhold * Revision 1.8 2007/12/03 01:49:49 mike
29*59d799daSIngo Weinhold * Update license
30*59d799daSIngo Weinhold *
31*59d799daSIngo Weinhold * Revision 1.7 2003/06/02 16:51:13 mike
32*59d799daSIngo Weinhold * *** empty log message ***
33*59d799daSIngo Weinhold *
34*59d799daSIngo Weinhold * Revision 1.6 2003/06/02 16:49:48 mike
35*59d799daSIngo Weinhold * tweak the decimal places
36*59d799daSIngo Weinhold *
37*59d799daSIngo Weinhold * Revision 1.5 2003/06/02 16:47:39 mike
38*59d799daSIngo Weinhold * tweak arctan algorithm some more
39*59d799daSIngo Weinhold *
40*59d799daSIngo Weinhold * Revision 1.4 2003/05/31 22:38:07 mike
41*59d799daSIngo Weinhold * optimize arctan by using fewer digits as subsequent
42*59d799daSIngo Weinhold * terms get smaller
43*59d799daSIngo Weinhold *
44*59d799daSIngo Weinhold * Revision 1.3 2002/11/03 21:36:43 mike
45*59d799daSIngo Weinhold * Updated function parameters to use the modern style
46*59d799daSIngo Weinhold *
47*59d799daSIngo Weinhold * Revision 1.2 2000/12/02 20:11:37 mike
48*59d799daSIngo Weinhold * add comments
49*59d799daSIngo Weinhold *
50*59d799daSIngo Weinhold * Revision 1.1 2000/12/02 20:08:27 mike
51*59d799daSIngo Weinhold * Initial revision
52*59d799daSIngo Weinhold */
53*59d799daSIngo Weinhold
54*59d799daSIngo Weinhold #include "m_apm_lc.h"
55*59d799daSIngo Weinhold
56*59d799daSIngo Weinhold /****************************************************************************/
57*59d799daSIngo Weinhold /*
58*59d799daSIngo Weinhold Calculate arcsin using the identity :
59*59d799daSIngo Weinhold
60*59d799daSIngo Weinhold x
61*59d799daSIngo Weinhold arcsin (x) == arctan [ --------------- ]
62*59d799daSIngo Weinhold sqrt(1 - x^2)
63*59d799daSIngo Weinhold
64*59d799daSIngo Weinhold */
M_arcsin_near_0(M_APM rr,int places,M_APM aa)65*59d799daSIngo Weinhold void M_arcsin_near_0(M_APM rr, int places, M_APM aa)
66*59d799daSIngo Weinhold {
67*59d799daSIngo Weinhold M_APM tmp5, tmp6;
68*59d799daSIngo Weinhold
69*59d799daSIngo Weinhold tmp5 = M_get_stack_var();
70*59d799daSIngo Weinhold tmp6 = M_get_stack_var();
71*59d799daSIngo Weinhold
72*59d799daSIngo Weinhold M_cos_to_sin(tmp5, (places + 8), aa);
73*59d799daSIngo Weinhold m_apm_divide(tmp6, (places + 8), aa, tmp5);
74*59d799daSIngo Weinhold M_arctan_near_0(rr, places, tmp6);
75*59d799daSIngo Weinhold
76*59d799daSIngo Weinhold M_restore_stack(2);
77*59d799daSIngo Weinhold }
78*59d799daSIngo Weinhold /****************************************************************************/
79*59d799daSIngo Weinhold /*
80*59d799daSIngo Weinhold Calculate arccos using the identity :
81*59d799daSIngo Weinhold
82*59d799daSIngo Weinhold arccos (x) == PI / 2 - arcsin (x)
83*59d799daSIngo Weinhold
84*59d799daSIngo Weinhold */
M_arccos_near_0(M_APM rr,int places,M_APM aa)85*59d799daSIngo Weinhold void M_arccos_near_0(M_APM rr, int places, M_APM aa)
86*59d799daSIngo Weinhold {
87*59d799daSIngo Weinhold M_APM tmp1, tmp2;
88*59d799daSIngo Weinhold
89*59d799daSIngo Weinhold tmp1 = M_get_stack_var();
90*59d799daSIngo Weinhold tmp2 = M_get_stack_var();
91*59d799daSIngo Weinhold
92*59d799daSIngo Weinhold M_check_PI_places(places);
93*59d799daSIngo Weinhold M_arcsin_near_0(tmp1, (places + 4), aa);
94*59d799daSIngo Weinhold m_apm_subtract(tmp2, MM_lc_HALF_PI, tmp1);
95*59d799daSIngo Weinhold m_apm_round(rr, places, tmp2);
96*59d799daSIngo Weinhold
97*59d799daSIngo Weinhold M_restore_stack(2);
98*59d799daSIngo Weinhold }
99*59d799daSIngo Weinhold /****************************************************************************/
100*59d799daSIngo Weinhold /*
101*59d799daSIngo Weinhold calculate arctan (x) with the following series:
102*59d799daSIngo Weinhold
103*59d799daSIngo Weinhold x^3 x^5 x^7 x^9
104*59d799daSIngo Weinhold arctan (x) = x - --- + --- - --- + --- ...
105*59d799daSIngo Weinhold 3 5 7 9
106*59d799daSIngo Weinhold
107*59d799daSIngo Weinhold */
M_arctan_near_0(M_APM rr,int places,M_APM aa)108*59d799daSIngo Weinhold void M_arctan_near_0(M_APM rr, int places, M_APM aa)
109*59d799daSIngo Weinhold {
110*59d799daSIngo Weinhold M_APM tmp0, tmp2, tmpR, tmpS, digit, term;
111*59d799daSIngo Weinhold int tolerance, dplaces, local_precision;
112*59d799daSIngo Weinhold long m1;
113*59d799daSIngo Weinhold
114*59d799daSIngo Weinhold tmp0 = M_get_stack_var();
115*59d799daSIngo Weinhold tmp2 = M_get_stack_var();
116*59d799daSIngo Weinhold tmpR = M_get_stack_var();
117*59d799daSIngo Weinhold tmpS = M_get_stack_var();
118*59d799daSIngo Weinhold term = M_get_stack_var();
119*59d799daSIngo Weinhold digit = M_get_stack_var();
120*59d799daSIngo Weinhold
121*59d799daSIngo Weinhold tolerance = aa->m_apm_exponent - (places + 4);
122*59d799daSIngo Weinhold dplaces = (places + 8) - aa->m_apm_exponent;
123*59d799daSIngo Weinhold
124*59d799daSIngo Weinhold m_apm_copy(term, aa);
125*59d799daSIngo Weinhold m_apm_copy(tmpS, aa);
126*59d799daSIngo Weinhold m_apm_multiply(tmp0, aa, aa);
127*59d799daSIngo Weinhold m_apm_round(tmp2, (dplaces + 8), tmp0);
128*59d799daSIngo Weinhold
129*59d799daSIngo Weinhold m1 = 1L;
130*59d799daSIngo Weinhold
131*59d799daSIngo Weinhold while (TRUE)
132*59d799daSIngo Weinhold {
133*59d799daSIngo Weinhold /*
134*59d799daSIngo Weinhold * do the subtraction term
135*59d799daSIngo Weinhold */
136*59d799daSIngo Weinhold
137*59d799daSIngo Weinhold m_apm_multiply(tmp0, term, tmp2);
138*59d799daSIngo Weinhold
139*59d799daSIngo Weinhold if ((tmp0->m_apm_exponent < tolerance) || (tmp0->m_apm_sign == 0))
140*59d799daSIngo Weinhold {
141*59d799daSIngo Weinhold m_apm_round(rr, places, tmpS);
142*59d799daSIngo Weinhold break;
143*59d799daSIngo Weinhold }
144*59d799daSIngo Weinhold
145*59d799daSIngo Weinhold local_precision = dplaces + tmp0->m_apm_exponent;
146*59d799daSIngo Weinhold
147*59d799daSIngo Weinhold if (local_precision < 20)
148*59d799daSIngo Weinhold local_precision = 20;
149*59d799daSIngo Weinhold
150*59d799daSIngo Weinhold m1 += 2;
151*59d799daSIngo Weinhold m_apm_set_long(digit, m1);
152*59d799daSIngo Weinhold m_apm_round(term, local_precision, tmp0);
153*59d799daSIngo Weinhold m_apm_divide(tmp0, local_precision, term, digit);
154*59d799daSIngo Weinhold m_apm_subtract(tmpR, tmpS, tmp0);
155*59d799daSIngo Weinhold
156*59d799daSIngo Weinhold /*
157*59d799daSIngo Weinhold * do the addition term
158*59d799daSIngo Weinhold */
159*59d799daSIngo Weinhold
160*59d799daSIngo Weinhold m_apm_multiply(tmp0, term, tmp2);
161*59d799daSIngo Weinhold
162*59d799daSIngo Weinhold if ((tmp0->m_apm_exponent < tolerance) || (tmp0->m_apm_sign == 0))
163*59d799daSIngo Weinhold {
164*59d799daSIngo Weinhold m_apm_round(rr, places, tmpR);
165*59d799daSIngo Weinhold break;
166*59d799daSIngo Weinhold }
167*59d799daSIngo Weinhold
168*59d799daSIngo Weinhold local_precision = dplaces + tmp0->m_apm_exponent;
169*59d799daSIngo Weinhold
170*59d799daSIngo Weinhold if (local_precision < 20)
171*59d799daSIngo Weinhold local_precision = 20;
172*59d799daSIngo Weinhold
173*59d799daSIngo Weinhold m1 += 2;
174*59d799daSIngo Weinhold m_apm_set_long(digit, m1);
175*59d799daSIngo Weinhold m_apm_round(term, local_precision, tmp0);
176*59d799daSIngo Weinhold m_apm_divide(tmp0, local_precision, term, digit);
177*59d799daSIngo Weinhold m_apm_add(tmpS, tmpR, tmp0);
178*59d799daSIngo Weinhold }
179*59d799daSIngo Weinhold
180*59d799daSIngo Weinhold M_restore_stack(6); /* restore the 6 locals we used here */
181*59d799daSIngo Weinhold }
182*59d799daSIngo Weinhold /****************************************************************************/
183