1177668d1SDavid Schultz 2177668d1SDavid Schultz /* @(#)e_log10.c 1.3 95/01/18 */ 3177668d1SDavid Schultz /* 4177668d1SDavid Schultz * ==================================================== 5177668d1SDavid Schultz * Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 6177668d1SDavid Schultz * 7177668d1SDavid Schultz * Developed at SunSoft, a Sun Microsystems, Inc. business. 8177668d1SDavid Schultz * Permission to use, copy, modify, and distribute this 9177668d1SDavid Schultz * software is freely granted, provided that this notice 10177668d1SDavid Schultz * is preserved. 11177668d1SDavid Schultz * ==================================================== 12177668d1SDavid Schultz */ 13177668d1SDavid Schultz 14177668d1SDavid Schultz #include <sys/cdefs.h> 15177668d1SDavid Schultz __FBSDID("$FreeBSD$"); 16177668d1SDavid Schultz 1763687c8bSDavid Schultz /* 185ebf26f6SDavid Schultz * Return the base 2 logarithm of x. See e_log.c and k_log.h for most 195ebf26f6SDavid Schultz * comments. 20b052ec90SDavid Schultz * 21b052ec90SDavid Schultz * This reduces x to {k, 1+f} exactly as in e_log.c, then calls the kernel, 22b052ec90SDavid Schultz * then does the combining and scaling steps 23b052ec90SDavid Schultz * log2(x) = (f - 0.5*f*f + k_log1p(f)) / ln2 + k 24b052ec90SDavid Schultz * in not-quite-routine extra precision. 25177668d1SDavid Schultz */ 26177668d1SDavid Schultz 27*0b8d0b5bSDavid Schultz #include <float.h> 28*0b8d0b5bSDavid Schultz 29177668d1SDavid Schultz #include "math.h" 30177668d1SDavid Schultz #include "math_private.h" 31177668d1SDavid Schultz #include "k_log.h" 32177668d1SDavid Schultz 33177668d1SDavid Schultz static const double 34177668d1SDavid Schultz two54 = 1.80143985094819840000e+16, /* 0x43500000, 0x00000000 */ 3563687c8bSDavid Schultz ivln2hi = 1.44269504072144627571e+00, /* 0x3ff71547, 0x65200000 */ 3663687c8bSDavid Schultz ivln2lo = 1.67517131648865118353e-10; /* 0x3de705fc, 0x2eefa200 */ 37177668d1SDavid Schultz 38177668d1SDavid Schultz static const double zero = 0.0; 397dbbb6ddSDavid Schultz static volatile double vzero = 0.0; 40177668d1SDavid Schultz 41177668d1SDavid Schultz double 42177668d1SDavid Schultz __ieee754_log2(double x) 43177668d1SDavid Schultz { 44b052ec90SDavid Schultz double f,hfsq,hi,lo,r,val_hi,val_lo,w,y; 45177668d1SDavid Schultz int32_t i,k,hx; 46177668d1SDavid Schultz u_int32_t lx; 47177668d1SDavid Schultz 48177668d1SDavid Schultz EXTRACT_WORDS(hx,lx,x); 49177668d1SDavid Schultz 50177668d1SDavid Schultz k=0; 51177668d1SDavid Schultz if (hx < 0x00100000) { /* x < 2**-1022 */ 52177668d1SDavid Schultz if (((hx&0x7fffffff)|lx)==0) 537dbbb6ddSDavid Schultz return -two54/vzero; /* log(+-0)=-inf */ 54177668d1SDavid Schultz if (hx<0) return (x-x)/zero; /* log(-#) = NaN */ 55177668d1SDavid Schultz k -= 54; x *= two54; /* subnormal number, scale up x */ 56177668d1SDavid Schultz GET_HIGH_WORD(hx,x); 57177668d1SDavid Schultz } 58177668d1SDavid Schultz if (hx >= 0x7ff00000) return x+x; 59b052ec90SDavid Schultz if (hx == 0x3ff00000 && lx == 0) 60b052ec90SDavid Schultz return zero; /* log(1) = +0 */ 61177668d1SDavid Schultz k += (hx>>20)-1023; 62177668d1SDavid Schultz hx &= 0x000fffff; 63177668d1SDavid Schultz i = (hx+0x95f64)&0x100000; 64177668d1SDavid Schultz SET_HIGH_WORD(x,hx|(i^0x3ff00000)); /* normalize x or x/2 */ 65177668d1SDavid Schultz k += (i>>20); 66b052ec90SDavid Schultz y = (double)k; 67b052ec90SDavid Schultz f = x - 1.0; 68b052ec90SDavid Schultz hfsq = 0.5*f*f; 69b052ec90SDavid Schultz r = k_log1p(f); 70b052ec90SDavid Schultz 71b052ec90SDavid Schultz /* 72b052ec90SDavid Schultz * f-hfsq must (for args near 1) be evaluated in extra precision 73b052ec90SDavid Schultz * to avoid a large cancellation when x is near sqrt(2) or 1/sqrt(2). 74b052ec90SDavid Schultz * This is fairly efficient since f-hfsq only depends on f, so can 75b052ec90SDavid Schultz * be evaluated in parallel with R. Not combining hfsq with R also 76b052ec90SDavid Schultz * keeps R small (though not as small as a true `lo' term would be), 77b052ec90SDavid Schultz * so that extra precision is not needed for terms involving R. 78b052ec90SDavid Schultz * 79b052ec90SDavid Schultz * Compiler bugs involving extra precision used to break Dekker's 80b052ec90SDavid Schultz * theorem for spitting f-hfsq as hi+lo, unless double_t was used 81b052ec90SDavid Schultz * or the multi-precision calculations were avoided when double_t 82b052ec90SDavid Schultz * has extra precision. These problems are now automatically 83b052ec90SDavid Schultz * avoided as a side effect of the optimization of combining the 84b052ec90SDavid Schultz * Dekker splitting step with the clear-low-bits step. 85b052ec90SDavid Schultz * 86b052ec90SDavid Schultz * y must (for args near sqrt(2) and 1/sqrt(2)) be added in extra 87b052ec90SDavid Schultz * precision to avoid a very large cancellation when x is very near 88b052ec90SDavid Schultz * these values. Unlike the above cancellations, this problem is 89b052ec90SDavid Schultz * specific to base 2. It is strange that adding +-1 is so much 90b052ec90SDavid Schultz * harder than adding +-ln2 or +-log10_2. 91b052ec90SDavid Schultz * 92b052ec90SDavid Schultz * This uses Dekker's theorem to normalize y+val_hi, so the 93b052ec90SDavid Schultz * compiler bugs are back in some configurations, sigh. And I 94b052ec90SDavid Schultz * don't want to used double_t to avoid them, since that gives a 95b052ec90SDavid Schultz * pessimization and the support for avoiding the pessimization 96b052ec90SDavid Schultz * is not yet available. 97b052ec90SDavid Schultz * 98b052ec90SDavid Schultz * The multi-precision calculations for the multiplications are 99b052ec90SDavid Schultz * routine. 100b052ec90SDavid Schultz */ 101b052ec90SDavid Schultz hi = f - hfsq; 102177668d1SDavid Schultz SET_LOW_WORD(hi,0); 103b052ec90SDavid Schultz lo = (f - hi) - hfsq + r; 104b052ec90SDavid Schultz val_hi = hi*ivln2hi; 105b052ec90SDavid Schultz val_lo = (lo+hi)*ivln2lo + lo*ivln2hi; 106b052ec90SDavid Schultz 107b052ec90SDavid Schultz /* spadd(val_hi, val_lo, y), except for not using double_t: */ 108b052ec90SDavid Schultz w = y + val_hi; 109b052ec90SDavid Schultz val_lo += (y - w) + val_hi; 110b052ec90SDavid Schultz val_hi = w; 111b052ec90SDavid Schultz 112b052ec90SDavid Schultz return val_lo + val_hi; 113177668d1SDavid Schultz } 11425a4d6bfSDavid Schultz 11525a4d6bfSDavid Schultz #if (LDBL_MANT_DIG == 53) 11625a4d6bfSDavid Schultz __weak_reference(log2, log2l); 11725a4d6bfSDavid Schultz #endif 118