122e1891291a7a9ae9f1fe0a9a34a731f74bc58d
[gnulib.git] / lib / expl.c
1 /* Emulation for expl.
2    Contributed by Paolo Bonzini
3
4    Copyright 2002, 2003 Free Software Foundation, Inc.
5
6    This file is part of gnulib.
7
8    gnulib is free software; you can redistribute it and/or modify it
9    under the terms of the GNU Lesser General Public License as published
10    by the Free Software Foundation; either version 2.1, or (at your option)
11    any later version.
12
13    gnulib is distributed in the hope that it will be useful, but WITHOUT
14    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
15    FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
16    License for more details.
17
18    You should have received a copy of the GNU Lesser General Public License
19    along with gnulib; see the file COPYING.LIB.  If not, write to the Free
20    Software Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307,
21    USA.
22  */
23
24 #include <float.h>
25 #include <math.h>
26
27 #include "mathl.h"
28
29 static const long double C[] = {
30 /* Chebyshev polynom coeficients for (exp(x)-1)/x */
31 #define P1 C[0]
32 #define P2 C[1]
33 #define P3 C[2]
34 #define P4 C[3]
35 #define P5 C[4]
36 #define P6 C[5]
37  0.5L,
38  1.66666666666666666666666666666666683E-01L,
39  4.16666666666666666666654902320001674E-02L,
40  8.33333333333333333333314659767198461E-03L,
41  1.38888888889899438565058018857254025E-03L,
42  1.98412698413981650382436541785404286E-04L,
43
44 /* Smallest integer x for which e^x overflows.  */
45 #define himark C[6]
46  11356.523406294143949491931077970765L,
47
48 /* Largest integer x for which e^x underflows.  */
49 #define lomark C[7]
50 -11433.4627433362978788372438434526231L,
51
52 /* very small number */
53 #define TINY C[8]
54  1.0e-4900L,
55
56 /* 2^16383 */
57 #define TWO16383 C[9]
58  5.94865747678615882542879663314003565E+4931L};
59
60 long double
61 expl (long double x)
62 {
63   /* Check for usual case.  */
64   if (x < himark && x > lomark)
65     {
66       int exponent;
67       long double t, x22;
68       int k = 1;
69       long double result = 1.0;
70
71       /* Compute an integer power of e with a granularity of 0.125.  */
72       exponent = (int) floorl (x * 8.0L);
73       x -= exponent / 8.0L;
74
75       if (x > 0.0625)
76         {
77           exponent++;
78           x -= 0.125L;
79         }
80
81       if (exponent < 0)
82         {
83           t = 0.8824969025845954028648921432290507362220L; /* e^-0.25 */
84           exponent = -exponent;
85         }
86       else
87         t = 1.1331484530668263168290072278117938725655L; /* e^0.25 */
88
89       while (exponent)
90         {
91           if (exponent & k)
92             {
93               result *= t;
94               exponent ^= k;
95             }
96           t *= t;
97           k <<= 1;
98         }
99
100       /* Approximate (e^x - 1)/x, using a seventh-degree polynomial,
101          with maximum error in [-2^-16-2^-53,2^-16+2^-53]
102          less than 4.8e-39.  */
103       x22 = x + x*x*(P1+x*(P2+x*(P3+x*(P4+x*(P5+x*P6)))));
104
105       return result + result * x22;
106     }
107   /* Exceptional cases:  */
108   else if (x < himark)
109     {
110       if (x + x == x)
111         /* e^-inf == 0, with no error.  */
112         return 0;
113       else
114         /* Underflow */
115         return TINY * TINY;
116     }
117   else
118     /* Return x, if x is a NaN or Inf; or overflow, otherwise.  */
119     return TWO16383*x;
120 }
121
122 #if 0
123 int
124 main ()
125 {
126   printf ("%.16Lg\n", expl(1.0L));
127   printf ("%.16Lg\n", expl(-1.0L));
128   printf ("%.16Lg\n", expl(2.0L));
129   printf ("%.16Lg\n", expl(4.0L));
130   printf ("%.16Lg\n", expl(-2.0L));
131   printf ("%.16Lg\n", expl(-4.0L));
132   printf ("%.16Lg\n", expl(0.0625L));
133   printf ("%.16Lg\n", expl(0.3L));
134   printf ("%.16Lg\n", expl(0.6L));
135 }
136 #endif