blob: eb06eb2244b1fb91e2a56046816b88c0411689cf [file] [log] [blame]
Christian Heimes53876d92008-04-19 00:31:39 +00001#include "Python.h"
2
Mark Dickinson87ec0852009-02-09 17:15:59 +00003#ifdef X87_DOUBLE_ROUNDING
4/* On x86 platforms using an x87 FPU, this function is called from the
5 Py_FORCE_DOUBLE macro (defined in pymath.h) to force a floating-point
6 number out of an 80-bit x87 FPU register and into a 64-bit memory location,
7 thus rounding from extended precision to double precision. */
8double _Py_force_double(double x)
9{
10 volatile double y;
11 y = x;
12 return y;
13}
14#endif
15
Mark Dickinsonb08a53a2009-04-16 19:52:09 +000016#ifdef USING_X87_FPU
17# ifdef HAVE_GCC_ASM_FOR_X87
18
19/* inline assembly for getting and setting the 387 FPU control word on
20 gcc/x86 */
21
22unsigned short _Py_get_387controlword(void) {
23 unsigned short cw;
24 __asm__ __volatile__ ("fnstcw %0" : "=m" (cw));
25 return cw;
26}
27
28void _Py_set_387controlword(unsigned short cw) {
29 __asm__ __volatile__ ("fldcw %0" : : "m" (cw));
30}
31
32# else
33# error "Unable to get and set x87 control word"
34# endif
35#endif
36
37
Christian Heimes53876d92008-04-19 00:31:39 +000038#ifndef HAVE_HYPOT
39double hypot(double x, double y)
40{
41 double yx;
42
43 x = fabs(x);
44 y = fabs(y);
45 if (x < y) {
46 double temp = x;
47 x = y;
48 y = temp;
49 }
50 if (x == 0.)
51 return 0.;
52 else {
53 yx = y/x;
54 return x*sqrt(1.+yx*yx);
55 }
56}
57#endif /* HAVE_HYPOT */
58
59#ifndef HAVE_COPYSIGN
60static double
61copysign(double x, double y)
62{
63 /* use atan2 to distinguish -0. from 0. */
64 if (y > 0. || (y == 0. && atan2(y, -1.) > 0.)) {
65 return fabs(x);
66 } else {
67 return -fabs(x);
68 }
69}
70#endif /* HAVE_COPYSIGN */
71
Mark Dickinsonf2537862009-04-18 13:58:18 +000072#ifndef HAVE_ROUND
73double
74round(double x)
75{
76 double absx, y;
77 absx = fabs(x);
78 y = floor(absx);
79 if (absx - y >= 0.5)
80 y += 1.0;
81 return copysign(y, x);
82}
83#endif /* HAVE_ROUND */
84
Christian Heimes53876d92008-04-19 00:31:39 +000085#ifndef HAVE_LOG1P
Andrew MacIntyre45612572008-09-22 14:49:01 +000086#include <float.h>
87
Christian Heimes53876d92008-04-19 00:31:39 +000088double
89log1p(double x)
90{
91 /* For x small, we use the following approach. Let y be the nearest
92 float to 1+x, then
93
94 1+x = y * (1 - (y-1-x)/y)
95
96 so log(1+x) = log(y) + log(1-(y-1-x)/y). Since (y-1-x)/y is tiny,
97 the second term is well approximated by (y-1-x)/y. If abs(x) >=
98 DBL_EPSILON/2 or the rounding-mode is some form of round-to-nearest
99 then y-1-x will be exactly representable, and is computed exactly
100 by (y-1)-x.
101
102 If abs(x) < DBL_EPSILON/2 and the rounding mode is not known to be
103 round-to-nearest then this method is slightly dangerous: 1+x could
104 be rounded up to 1+DBL_EPSILON instead of down to 1, and in that
105 case y-1-x will not be exactly representable any more and the
106 result can be off by many ulps. But this is easily fixed: for a
107 floating-point number |x| < DBL_EPSILON/2., the closest
108 floating-point number to log(1+x) is exactly x.
109 */
110
111 double y;
112 if (fabs(x) < DBL_EPSILON/2.) {
113 return x;
114 } else if (-0.5 <= x && x <= 1.) {
115 /* WARNING: it's possible than an overeager compiler
116 will incorrectly optimize the following two lines
117 to the equivalent of "return log(1.+x)". If this
118 happens, then results from log1p will be inaccurate
119 for small x. */
120 y = 1.+x;
121 return log(y)-((y-1.)-x)/y;
122 } else {
123 /* NaNs and infinities should end up here */
124 return log(1.+x);
125 }
126}
127#endif /* HAVE_LOG1P */
128
129/*
130 * ====================================================
131 * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
132 *
133 * Developed at SunPro, a Sun Microsystems, Inc. business.
134 * Permission to use, copy, modify, and distribute this
135 * software is freely granted, provided that this notice
136 * is preserved.
137 * ====================================================
138 */
139
140static const double ln2 = 6.93147180559945286227E-01;
141static const double two_pow_m28 = 3.7252902984619141E-09; /* 2**-28 */
142static const double two_pow_p28 = 268435456.0; /* 2**28 */
143static const double zero = 0.0;
144
145/* asinh(x)
146 * Method :
147 * Based on
148 * asinh(x) = sign(x) * log [ |x| + sqrt(x*x+1) ]
149 * we have
150 * asinh(x) := x if 1+x*x=1,
151 * := sign(x)*(log(x)+ln2)) for large |x|, else
152 * := sign(x)*log(2|x|+1/(|x|+sqrt(x*x+1))) if|x|>2, else
153 * := sign(x)*log1p(|x| + x^2/(1 + sqrt(1+x^2)))
154 */
155
156#ifndef HAVE_ASINH
157double
158asinh(double x)
159{
160 double w;
161 double absx = fabs(x);
162
163 if (Py_IS_NAN(x) || Py_IS_INFINITY(x)) {
164 return x+x;
165 }
166 if (absx < two_pow_m28) { /* |x| < 2**-28 */
167 return x; /* return x inexact except 0 */
168 }
169 if (absx > two_pow_p28) { /* |x| > 2**28 */
170 w = log(absx)+ln2;
171 }
172 else if (absx > 2.0) { /* 2 < |x| < 2**28 */
173 w = log(2.0*absx + 1.0 / (sqrt(x*x + 1.0) + absx));
174 }
175 else { /* 2**-28 <= |x| < 2= */
176 double t = x*x;
177 w = log1p(absx + t / (1.0 + sqrt(1.0 + t)));
178 }
179 return copysign(w, x);
180
181}
182#endif /* HAVE_ASINH */
183
184/* acosh(x)
185 * Method :
186 * Based on
187 * acosh(x) = log [ x + sqrt(x*x-1) ]
188 * we have
189 * acosh(x) := log(x)+ln2, if x is large; else
190 * acosh(x) := log(2x-1/(sqrt(x*x-1)+x)) if x>2; else
191 * acosh(x) := log1p(t+sqrt(2.0*t+t*t)); where t=x-1.
192 *
193 * Special cases:
194 * acosh(x) is NaN with signal if x<1.
195 * acosh(NaN) is NaN without signal.
196 */
197
198#ifndef HAVE_ACOSH
199double
200acosh(double x)
201{
202 if (Py_IS_NAN(x)) {
203 return x+x;
204 }
205 if (x < 1.) { /* x < 1; return a signaling NaN */
206 errno = EDOM;
207#ifdef Py_NAN
208 return Py_NAN;
209#else
210 return (x-x)/(x-x);
211#endif
212 }
213 else if (x >= two_pow_p28) { /* x > 2**28 */
214 if (Py_IS_INFINITY(x)) {
215 return x+x;
216 } else {
217 return log(x)+ln2; /* acosh(huge)=log(2x) */
218 }
219 }
220 else if (x == 1.) {
221 return 0.0; /* acosh(1) = 0 */
222 }
223 else if (x > 2.) { /* 2 < x < 2**28 */
224 double t = x*x;
225 return log(2.0*x - 1.0 / (x + sqrt(t - 1.0)));
226 }
227 else { /* 1 < x <= 2 */
228 double t = x - 1.0;
229 return log1p(t + sqrt(2.0*t + t*t));
230 }
231}
232#endif /* HAVE_ACOSH */
233
234/* atanh(x)
235 * Method :
236 * 1.Reduced x to positive by atanh(-x) = -atanh(x)
237 * 2.For x>=0.5
238 * 1 2x x
239 * atanh(x) = --- * log(1 + -------) = 0.5 * log1p(2 * --------)
240 * 2 1 - x 1 - x
241 *
242 * For x<0.5
243 * atanh(x) = 0.5*log1p(2x+2x*x/(1-x))
244 *
245 * Special cases:
246 * atanh(x) is NaN if |x| >= 1 with signal;
247 * atanh(NaN) is that NaN with no signal;
248 *
249 */
250
251#ifndef HAVE_ATANH
252double
253atanh(double x)
254{
255 double absx;
256 double t;
257
258 if (Py_IS_NAN(x)) {
259 return x+x;
260 }
261 absx = fabs(x);
262 if (absx >= 1.) { /* |x| >= 1 */
263 errno = EDOM;
264#ifdef Py_NAN
265 return Py_NAN;
266#else
267 return x/zero;
268#endif
269 }
270 if (absx < two_pow_m28) { /* |x| < 2**-28 */
271 return x;
272 }
273 if (absx < 0.5) { /* |x| < 0.5 */
274 t = absx+absx;
275 t = 0.5 * log1p(t + t*absx / (1.0 - absx));
276 }
277 else { /* 0.5 <= |x| <= 1.0 */
278 t = 0.5 * log1p((absx + absx) / (1.0 - absx));
279 }
280 return copysign(t, x);
281}
282#endif /* HAVE_ATANH */