1425bb815Sopenharmony_ci/* Copyright JS Foundation and other contributors, http://js.foundation 2425bb815Sopenharmony_ci * 3425bb815Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4425bb815Sopenharmony_ci * you may not use this file except in compliance with the License. 5425bb815Sopenharmony_ci * You may obtain a copy of the License at 6425bb815Sopenharmony_ci * 7425bb815Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8425bb815Sopenharmony_ci * 9425bb815Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10425bb815Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS 11425bb815Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12425bb815Sopenharmony_ci * See the License for the specific language governing permissions and 13425bb815Sopenharmony_ci * limitations under the License. 14425bb815Sopenharmony_ci * 15425bb815Sopenharmony_ci * This file is based on work under the following copyright and permission 16425bb815Sopenharmony_ci * notice: 17425bb815Sopenharmony_ci * 18425bb815Sopenharmony_ci * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 19425bb815Sopenharmony_ci * 20425bb815Sopenharmony_ci * Developed at SunSoft, a Sun Microsystems, Inc. business. 21425bb815Sopenharmony_ci * Permission to use, copy, modify, and distribute this 22425bb815Sopenharmony_ci * software is freely granted, provided that this notice 23425bb815Sopenharmony_ci * is preserved. 24425bb815Sopenharmony_ci * 25425bb815Sopenharmony_ci * @(#)e_log2.c 1.3 95/01/18 26425bb815Sopenharmony_ci */ 27425bb815Sopenharmony_ci 28425bb815Sopenharmony_ci#include "jerry-libm-internal.h" 29425bb815Sopenharmony_ci 30425bb815Sopenharmony_ci/* log2(x) 31425bb815Sopenharmony_ci * Return the base 2 logarithm of x. See e_log.c and k_log.h for most 32425bb815Sopenharmony_ci * comments. 33425bb815Sopenharmony_ci * 34425bb815Sopenharmony_ci * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel, 35425bb815Sopenharmony_ci * then does the combining and scaling steps 36425bb815Sopenharmony_ci * log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k 37425bb815Sopenharmony_ci * in not-quite-routine extra precision. 38425bb815Sopenharmony_ci */ 39425bb815Sopenharmony_ci 40425bb815Sopenharmony_ci#define zero 0.0 41425bb815Sopenharmony_ci#define two54 1.80143985094819840000e+16 /* 0x43500000, 0x00000000 */ 42425bb815Sopenharmony_ci#define ivln2hi 1.44269504072144627571e+00 /* 0x3FF71547, 0x65200000 */ 43425bb815Sopenharmony_ci#define ivln2lo 1.67517131648865118353e-10 /* 0x3DE705FC, 0x2EEFA200 */ 44425bb815Sopenharmony_ci#define Lg1 6.666666666666735130e-01 /* 0x3FE55555, 0x55555593 */ 45425bb815Sopenharmony_ci#define Lg2 3.999999999940941908e-01 /* 0x3FD99999, 0x9997FA04 */ 46425bb815Sopenharmony_ci#define Lg3 2.857142874366239149e-01 /* 0x3FD24924, 0x94229359 */ 47425bb815Sopenharmony_ci#define Lg4 2.222219843214978396e-01 /* 0x3FCC71C5, 0x1D8E78AF */ 48425bb815Sopenharmony_ci#define Lg5 1.818357216161805012e-01 /* 0x3FC74664, 0x96CB03DE */ 49425bb815Sopenharmony_ci#define Lg6 1.531383769920937332e-01 /* 0x3FC39A09, 0xD078C69F */ 50425bb815Sopenharmony_ci#define Lg7 1.479819860511658591e-01 /* 0x3FC2F112, 0xDF3E5244 */ 51425bb815Sopenharmony_ci 52425bb815Sopenharmony_cidouble 53425bb815Sopenharmony_cilog2 (double x) 54425bb815Sopenharmony_ci{ 55425bb815Sopenharmony_ci double f, hfsq, hi, lo, r, val_hi, val_lo, w, y; 56425bb815Sopenharmony_ci int i, k, hx; 57425bb815Sopenharmony_ci unsigned int lx; 58425bb815Sopenharmony_ci double_accessor temp; 59425bb815Sopenharmony_ci 60425bb815Sopenharmony_ci hx = __HI (x); /* high word of x */ 61425bb815Sopenharmony_ci lx = __LO (x); /* low word of x */ 62425bb815Sopenharmony_ci 63425bb815Sopenharmony_ci k = 0; 64425bb815Sopenharmony_ci if (hx < 0x00100000) 65425bb815Sopenharmony_ci { /* x < 2**-1022 */ 66425bb815Sopenharmony_ci if (((hx & 0x7fffffff) | lx) == 0) 67425bb815Sopenharmony_ci { 68425bb815Sopenharmony_ci return -two54 / zero; /* log(+-0)=-inf */ 69425bb815Sopenharmony_ci } 70425bb815Sopenharmony_ci if (hx < 0) 71425bb815Sopenharmony_ci { 72425bb815Sopenharmony_ci return (x - x) / zero; /* log(-#) = NaN */ 73425bb815Sopenharmony_ci } 74425bb815Sopenharmony_ci k -= 54; 75425bb815Sopenharmony_ci x *= two54; /* subnormal number, scale up x */ 76425bb815Sopenharmony_ci hx = __HI (x); /* high word of x */ 77425bb815Sopenharmony_ci } 78425bb815Sopenharmony_ci if (hx >= 0x7ff00000) 79425bb815Sopenharmony_ci { 80425bb815Sopenharmony_ci return x + x; 81425bb815Sopenharmony_ci } 82425bb815Sopenharmony_ci if (hx == 0x3ff00000 && lx == 0) 83425bb815Sopenharmony_ci { 84425bb815Sopenharmony_ci return zero; /* log(1) = +0 */ 85425bb815Sopenharmony_ci } 86425bb815Sopenharmony_ci k += (hx >> 20) - 1023; 87425bb815Sopenharmony_ci hx &= 0x000fffff; 88425bb815Sopenharmony_ci i = (hx + 0x95f64) & 0x100000; 89425bb815Sopenharmony_ci temp.dbl = x; 90425bb815Sopenharmony_ci temp.as_int.hi = hx | (i ^ 0x3ff00000); /* normalize x or x/2 */ 91425bb815Sopenharmony_ci k += (i >> 20); 92425bb815Sopenharmony_ci y = (double) k; 93425bb815Sopenharmony_ci f = temp.dbl - 1.0; 94425bb815Sopenharmony_ci hfsq = 0.5 * f * f; 95425bb815Sopenharmony_ci double s, z, R, t1, t2; 96425bb815Sopenharmony_ci 97425bb815Sopenharmony_ci s = f / (2.0 + f); 98425bb815Sopenharmony_ci z = s * s; 99425bb815Sopenharmony_ci w = z * z; 100425bb815Sopenharmony_ci t1 = w * (Lg2 + w * (Lg4 + w * Lg6)); 101425bb815Sopenharmony_ci t2 = z * (Lg1 + w * (Lg3 + w * (Lg5 + w * Lg7))); 102425bb815Sopenharmony_ci R = t2 + t1; 103425bb815Sopenharmony_ci r = s * (hfsq + R); 104425bb815Sopenharmony_ci /* 105425bb815Sopenharmony_ci * f-hfsq must (for args near 1) be evaluated in extra precision 106425bb815Sopenharmony_ci * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). 107425bb815Sopenharmony_ci * This is fairly efficient since f-hfsq only depends on f, so can 108425bb815Sopenharmony_ci * be evaluated in parallel with R. Not combining hfsq with R also 109425bb815Sopenharmony_ci * keeps R small (though not as small as a true `lo' term would be), 110425bb815Sopenharmony_ci * so that extra precision is not needed for terms involving R. 111425bb815Sopenharmony_ci * 112425bb815Sopenharmony_ci * Compiler bugs involving extra precision used to break Dekker's 113425bb815Sopenharmony_ci * theorem for spitting f-hfsq as hi+lo, unless double_t was used 114425bb815Sopenharmony_ci * or the multi-precision calculations were avoided when double_t 115425bb815Sopenharmony_ci * has extra precision. These problems are now automatically 116425bb815Sopenharmony_ci * avoided as a side effect of the optimization of combining the 117425bb815Sopenharmony_ci * Dekker splitting step with the clear-low-bits step. 118425bb815Sopenharmony_ci * 119425bb815Sopenharmony_ci * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra 120425bb815Sopenharmony_ci * precision to avoid a very large cancellation when x is very near 121425bb815Sopenharmony_ci * these values. Unlike the above cancellations, this problem is 122425bb815Sopenharmony_ci * specific to base 2. It is strange that adding +-1 is so much 123425bb815Sopenharmony_ci * harder than adding +-ln2 or +-log10_2. 124425bb815Sopenharmony_ci * 125425bb815Sopenharmony_ci * This uses Dekker's theorem to normalize y+val_hi, so the 126425bb815Sopenharmony_ci * compiler bugs are back in some configurations, sigh. And I 127425bb815Sopenharmony_ci * don't want to used double_t to avoid them, since that gives a 128425bb815Sopenharmony_ci * pessimization and the support for avoiding the pessimization 129425bb815Sopenharmony_ci * is not yet available. 130425bb815Sopenharmony_ci * 131425bb815Sopenharmony_ci * The multi-precision calculations for the multiplications are 132425bb815Sopenharmony_ci * routine. 133425bb815Sopenharmony_ci */ 134425bb815Sopenharmony_ci hi = f - hfsq; 135425bb815Sopenharmony_ci temp.dbl = hi; 136425bb815Sopenharmony_ci temp.as_int.lo = 0; 137425bb815Sopenharmony_ci 138425bb815Sopenharmony_ci lo = (f - hi) - hfsq + r; 139425bb815Sopenharmony_ci val_hi = hi * ivln2hi; 140425bb815Sopenharmony_ci val_lo = (lo + hi) * ivln2lo + lo * ivln2hi; 141425bb815Sopenharmony_ci 142425bb815Sopenharmony_ci /* spadd(val_hi, val_lo, y), except for not using double_t: */ 143425bb815Sopenharmony_ci w = y + val_hi; 144425bb815Sopenharmony_ci val_lo += (y - w) + val_hi; 145425bb815Sopenharmony_ci val_hi = w; 146425bb815Sopenharmony_ci 147425bb815Sopenharmony_ci return val_lo + val_hi; 148425bb815Sopenharmony_ci} /* log2 */ 149425bb815Sopenharmony_ci 150425bb815Sopenharmony_ci#undef zero 151425bb815Sopenharmony_ci#undef two54 152425bb815Sopenharmony_ci#undef ivln2hi 153425bb815Sopenharmony_ci#undef ivln2lo 154425bb815Sopenharmony_ci#undef Lg1 155425bb815Sopenharmony_ci#undef Lg2 156425bb815Sopenharmony_ci#undef Lg3 157425bb815Sopenharmony_ci#undef Lg4 158425bb815Sopenharmony_ci#undef Lg5 159425bb815Sopenharmony_ci#undef Lg6 160425bb815Sopenharmony_ci#undef Lg7 161