aboutsummaryrefslogtreecommitdiff
path: root/newlib/libm/mathfp/s_logarithm.c
blob: e8c24200ac581eac2d97460123a472f236f595e9 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133

/* @(#)z_logarithm.c 1.0 98/08/13 */
/******************************************************************
 * The following routines are coded directly from the algorithms
 * and coefficients given in "Software Manual for the Elementary
 * Functions" by William J. Cody, Jr. and William Waite, Prentice
 * Hall, 1980.
 ******************************************************************/

/*
FUNCTION
       <<log>>, <<logf>>, <<log10>>, <<log10f>>, <<logarithm>>, <<logarithmf>>---natural or base 10 logarithms

INDEX
    log
INDEX
    logf
INDEX
    log10
INDEX
    log10f

SYNOPSIS
       #include <math.h>
       double log(double <[x]>);
       float logf(float <[x]>);
       double log10(double <[x]>);
       float log10f(float <[x]>);

DESCRIPTION
Return the natural or base 10 logarithm of <[x]>, that is, its logarithm base e
(where e is the base of the natural system of logarithms, 2.71828@dots{}) or
base 10.
<<log>> and <<logf>> are identical save for the return and argument types.
<<log10>> and <<log10f>> are identical save for the return and argument types.

RETURNS
Normally, returns the calculated value.  When <[x]> is zero, the
returned value is <<-HUGE_VAL>> and <<errno>> is set to <<ERANGE>>.
When <[x]> is negative, the returned value is <<-HUGE_VAL>> and
<<errno>> is set to <<EDOM>>.  You can control the error behavior via
<<matherr>>.

PORTABILITY
<<log>> is ANSI. <<logf>> is an extension.

<<log10>> is ANSI. <<log10f>> is an extension.
*/


/******************************************************************
 * Logarithm
 *
 * Input:
 *   x - floating point value
 *   ten - indicates base ten numbers
 *
 * Output:
 *   logarithm of x
 *
 * Description:
 *   This routine calculates logarithms.
 *
 *****************************************************************/

#include "fdlibm.h"
#include "zmath.h"

#ifndef _DOUBLE_IS_32BITS

static const double a[] = { -0.64124943423745581147e+02,
                             0.16383943563021534222e+02,
                            -0.78956112887481257267 };
static const double b[] = { -0.76949932108494879777e+03,
                             0.31203222091924532844e+03,
                            -0.35667977739034646171e+02 };
static const double C1 =  22713.0 / 32768.0;
static const double C2 =  1.428606820309417232e-06;
static const double C3 =  0.43429448190325182765;

double
logarithm (double x,
        int ten)
{
  int N;
  double f, w, z;

  /* Check for range and domain errors here. */
  if (x == 0.0)
    {
      errno = ERANGE;
      return (-z_infinity.d);
    }
  else if (x < 0.0)
    {
      errno = EDOM;
      return (z_notanum.d);
    }
  else if (!isfinite(x))
    {
      if (isnan(x))
        return (z_notanum.d);
      else
        return (z_infinity.d);
    }

  /* Get the exponent and mantissa where x = f * 2^N. */
  f = frexp (x, &N);

  z = f - 0.5;

  if (f > __SQRT_HALF)
    z = (z - 0.5) / (f * 0.5 + 0.5);
  else
    {
      N--;
      z /= (z * 0.5 + 0.5);
    }
  w = z * z;

  /* Use Newton's method with 4 terms. */
  z += z * w * ((a[2] * w + a[1]) * w + a[0]) / (((w + b[2]) * w + b[1]) * w + b[0]);

  if (N != 0)
    z = (N * C2 + z) + N * C1;

  if (ten)
    z *= C3;

  return (z);
}

#endif /* _DOUBLE_IS_32BITS */