1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Single-precision log2 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 "log2f_data.h" 12570af302Sopenharmony_ci 13570af302Sopenharmony_ci/* 14570af302Sopenharmony_ciLOG2F_TABLE_BITS = 4 15570af302Sopenharmony_ciLOG2F_POLY_ORDER = 4 16570af302Sopenharmony_ci 17570af302Sopenharmony_ciULP error: 0.752 (nearest rounding.) 18570af302Sopenharmony_ciRelative error: 1.9 * 2^-26 (before rounding.) 19570af302Sopenharmony_ci*/ 20570af302Sopenharmony_ci 21570af302Sopenharmony_ci#define N (1 << LOG2F_TABLE_BITS) 22570af302Sopenharmony_ci#define T __log2f_data.tab 23570af302Sopenharmony_ci#define A __log2f_data.poly 24570af302Sopenharmony_ci#define OFF 0x3f330000 25570af302Sopenharmony_ci 26570af302Sopenharmony_cifloat log2f(float x) 27570af302Sopenharmony_ci{ 28570af302Sopenharmony_ci double_t z, r, r2, p, y, y0, invc, logc; 29570af302Sopenharmony_ci uint32_t ix, iz, top, tmp; 30570af302Sopenharmony_ci int k, i; 31570af302Sopenharmony_ci 32570af302Sopenharmony_ci ix = asuint(x); 33570af302Sopenharmony_ci /* Fix sign of zero with downward rounding when x==1. */ 34570af302Sopenharmony_ci if (WANT_ROUNDING && predict_false(ix == 0x3f800000)) 35570af302Sopenharmony_ci return 0; 36570af302Sopenharmony_ci if (predict_false(ix - 0x00800000 >= 0x7f800000 - 0x00800000)) { 37570af302Sopenharmony_ci /* x < 0x1p-126 or inf or nan. */ 38570af302Sopenharmony_ci if (ix * 2 == 0) 39570af302Sopenharmony_ci return __math_divzerof(1); 40570af302Sopenharmony_ci if (ix == 0x7f800000) /* log2(inf) == inf. */ 41570af302Sopenharmony_ci return x; 42570af302Sopenharmony_ci if ((ix & 0x80000000) || ix * 2 >= 0xff000000) 43570af302Sopenharmony_ci return __math_invalidf(x); 44570af302Sopenharmony_ci /* x is subnormal, normalize it. */ 45570af302Sopenharmony_ci ix = asuint(x * 0x1p23f); 46570af302Sopenharmony_ci ix -= 23 << 23; 47570af302Sopenharmony_ci } 48570af302Sopenharmony_ci 49570af302Sopenharmony_ci /* x = 2^k z; where z is in range [OFF,2*OFF] and exact. 50570af302Sopenharmony_ci The range is split into N subintervals. 51570af302Sopenharmony_ci The ith subinterval contains z and c is near its center. */ 52570af302Sopenharmony_ci tmp = ix - OFF; 53570af302Sopenharmony_ci i = (tmp >> (23 - LOG2F_TABLE_BITS)) % N; 54570af302Sopenharmony_ci top = tmp & 0xff800000; 55570af302Sopenharmony_ci iz = ix - top; 56570af302Sopenharmony_ci k = (int32_t)tmp >> 23; /* arithmetic shift */ 57570af302Sopenharmony_ci invc = T[i].invc; 58570af302Sopenharmony_ci logc = T[i].logc; 59570af302Sopenharmony_ci z = (double_t)asfloat(iz); 60570af302Sopenharmony_ci 61570af302Sopenharmony_ci /* log2(x) = log1p(z/c-1)/ln2 + log2(c) + k */ 62570af302Sopenharmony_ci r = z * invc - 1; 63570af302Sopenharmony_ci y0 = logc + (double_t)k; 64570af302Sopenharmony_ci 65570af302Sopenharmony_ci /* Pipelined polynomial evaluation to approximate log1p(r)/ln2. */ 66570af302Sopenharmony_ci r2 = r * r; 67570af302Sopenharmony_ci y = A[1] * r + A[2]; 68570af302Sopenharmony_ci y = A[0] * r2 + y; 69570af302Sopenharmony_ci p = A[3] * r + y0; 70570af302Sopenharmony_ci y = y * r2 + p; 71570af302Sopenharmony_ci return eval_as_float(y); 72570af302Sopenharmony_ci} 73