1bbbf1280Sopenharmony_ci/*
2bbbf1280Sopenharmony_ci * Single-precision log function.
3bbbf1280Sopenharmony_ci *
4bbbf1280Sopenharmony_ci * Copyright (c) 2017-2019, Arm Limited.
5bbbf1280Sopenharmony_ci * SPDX-License-Identifier: MIT
6bbbf1280Sopenharmony_ci */
7bbbf1280Sopenharmony_ci
8bbbf1280Sopenharmony_ci#include <math.h>
9bbbf1280Sopenharmony_ci#include <stdint.h>
10bbbf1280Sopenharmony_ci#include "math_config.h"
11bbbf1280Sopenharmony_ci
12bbbf1280Sopenharmony_ci/*
13bbbf1280Sopenharmony_ciLOGF_TABLE_BITS = 4
14bbbf1280Sopenharmony_ciLOGF_POLY_ORDER = 4
15bbbf1280Sopenharmony_ci
16bbbf1280Sopenharmony_ciULP error: 0.818 (nearest rounding.)
17bbbf1280Sopenharmony_ciRelative error: 1.957 * 2^-26 (before rounding.)
18bbbf1280Sopenharmony_ci*/
19bbbf1280Sopenharmony_ci
20bbbf1280Sopenharmony_ci#define T __logf_data.tab
21bbbf1280Sopenharmony_ci#define A __logf_data.poly
22bbbf1280Sopenharmony_ci#define Ln2 __logf_data.ln2
23bbbf1280Sopenharmony_ci#define N (1 << LOGF_TABLE_BITS)
24bbbf1280Sopenharmony_ci#define OFF 0x3f330000
25bbbf1280Sopenharmony_ci
26bbbf1280Sopenharmony_cifloat
27bbbf1280Sopenharmony_cilogf (float x)
28bbbf1280Sopenharmony_ci{
29bbbf1280Sopenharmony_ci  /* double_t for better performance on targets with FLT_EVAL_METHOD==2.  */
30bbbf1280Sopenharmony_ci  double_t z, r, r2, y, y0, invc, logc;
31bbbf1280Sopenharmony_ci  uint32_t ix, iz, tmp;
32bbbf1280Sopenharmony_ci  int k, i;
33bbbf1280Sopenharmony_ci
34bbbf1280Sopenharmony_ci  ix = asuint (x);
35bbbf1280Sopenharmony_ci#if WANT_ROUNDING
36bbbf1280Sopenharmony_ci  /* Fix sign of zero with downward rounding when x==1.  */
37bbbf1280Sopenharmony_ci  if (unlikely (ix == 0x3f800000))
38bbbf1280Sopenharmony_ci    return 0;
39bbbf1280Sopenharmony_ci#endif
40bbbf1280Sopenharmony_ci  if (unlikely (ix - 0x00800000 >= 0x7f800000 - 0x00800000))
41bbbf1280Sopenharmony_ci    {
42bbbf1280Sopenharmony_ci      /* x < 0x1p-126 or inf or nan.  */
43bbbf1280Sopenharmony_ci      if (ix * 2 == 0)
44bbbf1280Sopenharmony_ci	return __math_divzerof (1);
45bbbf1280Sopenharmony_ci      if (ix == 0x7f800000) /* log(inf) == inf.  */
46bbbf1280Sopenharmony_ci	return x;
47bbbf1280Sopenharmony_ci      if ((ix & 0x80000000) || ix * 2 >= 0xff000000)
48bbbf1280Sopenharmony_ci	return __math_invalidf (x);
49bbbf1280Sopenharmony_ci      /* x is subnormal, normalize it.  */
50bbbf1280Sopenharmony_ci      ix = asuint (x * 0x1p23f);
51bbbf1280Sopenharmony_ci      ix -= 23 << 23;
52bbbf1280Sopenharmony_ci    }
53bbbf1280Sopenharmony_ci
54bbbf1280Sopenharmony_ci  /* x = 2^k z; where z is in range [OFF,2*OFF] and exact.
55bbbf1280Sopenharmony_ci     The range is split into N subintervals.
56bbbf1280Sopenharmony_ci     The ith subinterval contains z and c is near its center.  */
57bbbf1280Sopenharmony_ci  tmp = ix - OFF;
58bbbf1280Sopenharmony_ci  i = (tmp >> (23 - LOGF_TABLE_BITS)) % N;
59bbbf1280Sopenharmony_ci  k = (int32_t) tmp >> 23; /* arithmetic shift */
60bbbf1280Sopenharmony_ci  iz = ix - (tmp & 0x1ff << 23);
61bbbf1280Sopenharmony_ci  invc = T[i].invc;
62bbbf1280Sopenharmony_ci  logc = T[i].logc;
63bbbf1280Sopenharmony_ci  z = (double_t) asfloat (iz);
64bbbf1280Sopenharmony_ci
65bbbf1280Sopenharmony_ci  /* log(x) = log1p(z/c-1) + log(c) + k*Ln2 */
66bbbf1280Sopenharmony_ci  r = z * invc - 1;
67bbbf1280Sopenharmony_ci  y0 = logc + (double_t) k * Ln2;
68bbbf1280Sopenharmony_ci
69bbbf1280Sopenharmony_ci  /* Pipelined polynomial evaluation to approximate log1p(r).  */
70bbbf1280Sopenharmony_ci  r2 = r * r;
71bbbf1280Sopenharmony_ci  y = A[1] * r + A[2];
72bbbf1280Sopenharmony_ci  y = A[0] * r2 + y;
73bbbf1280Sopenharmony_ci  y = y * r2 + (y0 + r);
74bbbf1280Sopenharmony_ci  return eval_as_float (y);
75bbbf1280Sopenharmony_ci}
76bbbf1280Sopenharmony_ci#if USE_GLIBC_ABI
77bbbf1280Sopenharmony_cistrong_alias (logf, __logf_finite)
78bbbf1280Sopenharmony_cihidden_alias (logf, __ieee754_logf)
79bbbf1280Sopenharmony_ci#endif
80