1570af302Sopenharmony_ci/* 2570af302Sopenharmony_ci * Single-precision 2^x 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 "exp2f_data.h" 12570af302Sopenharmony_ci 13570af302Sopenharmony_ci/* 14570af302Sopenharmony_ciEXP2F_TABLE_BITS = 5 15570af302Sopenharmony_ciEXP2F_POLY_ORDER = 3 16570af302Sopenharmony_ci 17570af302Sopenharmony_ciULP error: 0.502 (nearest rounding.) 18570af302Sopenharmony_ciRelative error: 1.69 * 2^-34 in [-1/64, 1/64] (before rounding.) 19570af302Sopenharmony_ciWrong count: 168353 (all nearest rounding wrong results with fma.) 20570af302Sopenharmony_ciNon-nearest ULP error: 1 (rounded ULP error) 21570af302Sopenharmony_ci*/ 22570af302Sopenharmony_ci 23570af302Sopenharmony_ci#define N (1 << EXP2F_TABLE_BITS) 24570af302Sopenharmony_ci#define T __exp2f_data.tab 25570af302Sopenharmony_ci#define C __exp2f_data.poly 26570af302Sopenharmony_ci#define SHIFT __exp2f_data.shift_scaled 27570af302Sopenharmony_ci 28570af302Sopenharmony_cistatic inline uint32_t top12(float x) 29570af302Sopenharmony_ci{ 30570af302Sopenharmony_ci return asuint(x) >> 20; 31570af302Sopenharmony_ci} 32570af302Sopenharmony_ci 33570af302Sopenharmony_cifloat exp2f(float x) 34570af302Sopenharmony_ci{ 35570af302Sopenharmony_ci uint32_t abstop; 36570af302Sopenharmony_ci uint64_t ki, t; 37570af302Sopenharmony_ci double_t kd, xd, z, r, r2, y, s; 38570af302Sopenharmony_ci 39570af302Sopenharmony_ci xd = (double_t)x; 40570af302Sopenharmony_ci abstop = top12(x) & 0x7ff; 41570af302Sopenharmony_ci if (predict_false(abstop >= top12(128.0f))) { 42570af302Sopenharmony_ci /* |x| >= 128 or x is nan. */ 43570af302Sopenharmony_ci if (asuint(x) == asuint(-INFINITY)) 44570af302Sopenharmony_ci return 0.0f; 45570af302Sopenharmony_ci if (abstop >= top12(INFINITY)) 46570af302Sopenharmony_ci return x + x; 47570af302Sopenharmony_ci if (x > 0.0f) 48570af302Sopenharmony_ci return __math_oflowf(0); 49570af302Sopenharmony_ci if (x <= -150.0f) 50570af302Sopenharmony_ci return __math_uflowf(0); 51570af302Sopenharmony_ci } 52570af302Sopenharmony_ci 53570af302Sopenharmony_ci /* x = k/N + r with r in [-1/(2N), 1/(2N)] and int k. */ 54570af302Sopenharmony_ci kd = eval_as_double(xd + SHIFT); 55570af302Sopenharmony_ci ki = asuint64(kd); 56570af302Sopenharmony_ci kd -= SHIFT; /* k/N for int k. */ 57570af302Sopenharmony_ci r = xd - kd; 58570af302Sopenharmony_ci 59570af302Sopenharmony_ci /* exp2(x) = 2^(k/N) * 2^r ~= s * (C0*r^3 + C1*r^2 + C2*r + 1) */ 60570af302Sopenharmony_ci t = T[ki % N]; 61570af302Sopenharmony_ci t += ki << (52 - EXP2F_TABLE_BITS); 62570af302Sopenharmony_ci s = asdouble(t); 63570af302Sopenharmony_ci z = C[0] * r + C[1]; 64570af302Sopenharmony_ci r2 = r * r; 65570af302Sopenharmony_ci y = C[2] * r + 1; 66570af302Sopenharmony_ci y = z * r2 + y; 67570af302Sopenharmony_ci y = y * s; 68570af302Sopenharmony_ci return eval_as_float(y); 69570af302Sopenharmony_ci} 70