1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Single-precision log function. 3570af302Sopenharmony_ci * 4570af302Sopenharmony_ci * Copyright (c) 2017-2018, Arm Limited. 5570af302Sopenharmony_ci * SPDX-License-Identifier: MIT 6570af302Sopenharmony_ci */ 7570af302Sopenharmony_ci 8570af302Sopenharmony_ci#include <math.h> 9570af302Sopenharmony_ci#include <stdint.h> 10570af302Sopenharmony_ci#include "libm.h" 11570af302Sopenharmony_ci#include "logf_data.h" 12570af302Sopenharmony_ci 13570af302Sopenharmony_ci/* 14570af302Sopenharmony_ciLOGF_TABLE_BITS = 4 15570af302Sopenharmony_ciLOGF_POLY_ORDER = 4 16570af302Sopenharmony_ci 17570af302Sopenharmony_ciULP error: 0.818 (nearest rounding.) 18570af302Sopenharmony_ciRelative error: 1.957 * 2^-26 (before rounding.) 19570af302Sopenharmony_ci*/ 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci#define T __logf_data.tab 22570af302Sopenharmony_ci#define A __logf_data.poly 23570af302Sopenharmony_ci#define Ln2 __logf_data.ln2 24570af302Sopenharmony_ci#define N (1 << LOGF_TABLE_BITS) 25570af302Sopenharmony_ci#define OFF 0x3f330000 26570af302Sopenharmony_ci 27570af302Sopenharmony_cifloat logf(float x) 28570af302Sopenharmony_ci{ 29570af302Sopenharmony_ci double_t z, r, r2, y, y0, invc, logc; 30570af302Sopenharmony_ci uint32_t ix, iz, tmp; 31570af302Sopenharmony_ci int k, i; 32570af302Sopenharmony_ci 33570af302Sopenharmony_ci ix = asuint(x); 34570af302Sopenharmony_ci /* Fix sign of zero with downward rounding when x==1. */ 35570af302Sopenharmony_ci if (WANT_ROUNDING && predict_false(ix == 0x3f800000)) 36570af302Sopenharmony_ci return 0; 37570af302Sopenharmony_ci if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) { 38570af302Sopenharmony_ci /* x < 0x1p-126 or inf or nan. */ 39570af302Sopenharmony_ci if (ix * 2 == 0) 40570af302Sopenharmony_ci return __math_divzerof(1); 41570af302Sopenharmony_ci if (ix == 0x7f800000) /* log(inf) == inf. */ 42570af302Sopenharmony_ci return x; 43570af302Sopenharmony_ci if ((ix & 0x80000000) || ix * 2 >= 0xff000000) 44570af302Sopenharmony_ci return __math_invalidf(x); 45570af302Sopenharmony_ci /* x is subnormal, normalize it. */ 46570af302Sopenharmony_ci ix = asuint(x * 0x1p23f); 47570af302Sopenharmony_ci ix -= 23 << 23; 48570af302Sopenharmony_ci } 49570af302Sopenharmony_ci 50570af302Sopenharmony_ci /* x = 2^k z; where z is in range [OFF,2*OFF] and exact. 51570af302Sopenharmony_ci The range is split into N subintervals. 52570af302Sopenharmony_ci The ith subinterval contains z and c is near its center. */ 53570af302Sopenharmony_ci tmp = ix - OFF; 54570af302Sopenharmony_ci i = (tmp >> (23 - LOGF_TABLE_BITS)) % N; 55570af302Sopenharmony_ci k = (int32_t)tmp >> 23; /* arithmetic shift */ 56570af302Sopenharmony_ci iz = ix - (tmp & 0xff800000); 57570af302Sopenharmony_ci invc = T[i].invc; 58570af302Sopenharmony_ci logc = T[i].logc; 59570af302Sopenharmony_ci z = (double_t)asfloat(iz); 60570af302Sopenharmony_ci 61570af302Sopenharmony_ci /* log(x) = log1p(z/c-1) + log(c) + k*Ln2 */ 62570af302Sopenharmony_ci r = z * invc - 1; 63570af302Sopenharmony_ci y0 = logc + (double_t)k * Ln2; 64570af302Sopenharmony_ci 65570af302Sopenharmony_ci /* Pipelined polynomial evaluation to approximate log1p(r). */ 66570af302Sopenharmony_ci r2 = r * r; 67570af302Sopenharmony_ci y = A[1] * r + A[2]; 68570af302Sopenharmony_ci y = A[0] * r2 + y; 69570af302Sopenharmony_ci y = y * r2 + (y0 + r); 70570af302Sopenharmony_ci return eval_as_float(y); 71570af302Sopenharmony_ci} 72