5 * Copyright (C) 2000 - 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.
22 * $Id: mapmcbrt.c,v 1.8 2007/12/03 01:50:32 mike Exp $
24 * This file contains the CBRT (cube root) function.
26 * $Log: mapmcbrt.c,v $
27 * Revision 1.8 2007/12/03 01:50:32 mike
30 * Revision 1.7 2003/05/05 18:17:38 mike
33 * Revision 1.6 2003/04/16 16:55:58 mike
34 * use new faster algorithm which finds 1 / cbrt(N)
36 * Revision 1.5 2002/11/03 21:34:34 mike
37 * Updated function parameters to use the modern style
39 * Revision 1.4 2000/10/30 16:42:22 mike
40 * minor speed optimization
42 * Revision 1.3 2000/07/11 18:03:39 mike
43 * make better estimate for initial precision
45 * Revision 1.2 2000/04/08 18:34:35 mike
46 * added some more comments
48 * Revision 1.1 2000/04/03 17:58:04 mike
54 /****************************************************************************/
55 void m_apm_cbrt(M_APM rr
, int places
, M_APM aa
)
57 M_APM last_x
, guess
, tmpN
, tmp7
, tmp8
, tmp9
;
58 int ii
, nexp
, bflag
, tolerance
, maxp
, local_precision
;
60 /* result is 0 if input is 0 */
62 if (aa
->m_apm_sign
== 0)
68 last_x
= M_get_stack_var();
69 guess
= M_get_stack_var();
70 tmpN
= M_get_stack_var();
71 tmp7
= M_get_stack_var();
72 tmp8
= M_get_stack_var();
73 tmp9
= M_get_stack_var();
75 /* compute the cube root of the positive number, we'll fix the sign later */
77 m_apm_absolute_value(tmpN
, aa
);
80 normalize the input number (make the exponent near 0) so
81 the 'guess' function will not over/under flow on large
85 nexp
= aa
->m_apm_exponent
/ 3;
86 tmpN
->m_apm_exponent
-= 3 * nexp
;
88 M_get_cbrt_guess(guess
, tmpN
);
90 tolerance
= places
+ 4;
95 m_apm_negate(last_x
, MM_Ten
);
97 /* Use the following iteration to calculate 1 / cbrt(N) :
100 X = [ 4 * X - N * X ] / 3
108 m_apm_multiply(tmp8
, guess
, guess
);
109 m_apm_multiply(tmp7
, tmp8
, tmp8
);
110 m_apm_round(tmp8
, local_precision
, tmp7
);
111 m_apm_multiply(tmp9
, tmpN
, tmp8
);
113 m_apm_multiply(tmp8
, MM_Four
, guess
);
114 m_apm_subtract(tmp7
, tmp8
, tmp9
);
115 m_apm_divide(guess
, local_precision
, tmp7
, MM_Three
);
120 /* force at least 2 iterations so 'last_x' has valid data */
124 m_apm_subtract(tmp8
, guess
, last_x
);
126 if (tmp8
->m_apm_sign
== 0)
129 if ((-4 * tmp8
->m_apm_exponent
) > tolerance
)
133 local_precision
*= 2;
135 if (local_precision
> maxp
)
136 local_precision
= maxp
;
138 m_apm_copy(last_x
, guess
);
142 /* final cbrt = N * guess ^ 2 */
144 m_apm_multiply(tmp9
, guess
, guess
);
145 m_apm_multiply(tmp8
, tmp9
, tmpN
);
146 m_apm_round(rr
, places
, tmp8
);
148 rr
->m_apm_exponent
+= nexp
;
149 rr
->m_apm_sign
= aa
->m_apm_sign
;
152 /****************************************************************************/