github.com/twelsh-aw/go/src@v0.0.0-20230516233729-a56fe86a7c81/math/log.go (about) 1 // Copyright 2009 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package math 6 7 /* 8 Floating-point logarithm. 9 */ 10 11 // The original C code, the long comment, and the constants 12 // below are from FreeBSD's /usr/src/lib/msun/src/e_log.c 13 // and came with this notice. The go code is a simpler 14 // version of the original C. 15 // 16 // ==================================================== 17 // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved. 18 // 19 // Developed at SunPro, a Sun Microsystems, Inc. business. 20 // Permission to use, copy, modify, and distribute this 21 // software is freely granted, provided that this notice 22 // is preserved. 23 // ==================================================== 24 // 25 // __ieee754_log(x) 26 // Return the logarithm of x 27 // 28 // Method : 29 // 1. Argument Reduction: find k and f such that 30 // x = 2**k * (1+f), 31 // where sqrt(2)/2 < 1+f < sqrt(2) . 32 // 33 // 2. Approximation of log(1+f). 34 // Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s) 35 // = 2s + 2/3 s**3 + 2/5 s**5 + ....., 36 // = 2s + s*R 37 // We use a special Reme algorithm on [0,0.1716] to generate 38 // a polynomial of degree 14 to approximate R. The maximum error 39 // of this polynomial approximation is bounded by 2**-58.45. In 40 // other words, 41 // 2 4 6 8 10 12 14 42 // R(z) ~ L1*s +L2*s +L3*s +L4*s +L5*s +L6*s +L7*s 43 // (the values of L1 to L7 are listed in the program) and 44 // | 2 14 | -58.45 45 // | L1*s +...+L7*s - R(z) | <= 2 46 // | | 47 // Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2. 48 // In order to guarantee error in log below 1ulp, we compute log by 49 // log(1+f) = f - s*(f - R) (if f is not too large) 50 // log(1+f) = f - (hfsq - s*(hfsq+R)). (better accuracy) 51 // 52 // 3. Finally, log(x) = k*Ln2 + log(1+f). 53 // = k*Ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*Ln2_lo))) 54 // Here Ln2 is split into two floating point number: 55 // Ln2_hi + Ln2_lo, 56 // where n*Ln2_hi is always exact for |n| < 2000. 57 // 58 // Special cases: 59 // log(x) is NaN with signal if x < 0 (including -INF) ; 60 // log(+INF) is +INF; log(0) is -INF with signal; 61 // log(NaN) is that NaN with no signal. 62 // 63 // Accuracy: 64 // according to an error analysis, the error is always less than 65 // 1 ulp (unit in the last place). 66 // 67 // Constants: 68 // The hexadecimal values are the intended ones for the following 69 // constants. The decimal values may be used, provided that the 70 // compiler will convert from decimal to binary accurately enough 71 // to produce the hexadecimal values shown. 72 73 // Log returns the natural logarithm of x. 74 // 75 // Special cases are: 76 // 77 // Log(+Inf) = +Inf 78 // Log(0) = -Inf 79 // Log(x < 0) = NaN 80 // Log(NaN) = NaN 81 func Log(x float64) float64 { 82 if haveArchLog { 83 return archLog(x) 84 } 85 return log(x) 86 } 87 88 func log(x float64) float64 { 89 const ( 90 Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */ 91 Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */ 92 L1 = 6.666666666666735130e-01 /* 3FE55555 55555593 */ 93 L2 = 3.999999999940941908e-01 /* 3FD99999 9997FA04 */ 94 L3 = 2.857142874366239149e-01 /* 3FD24924 94229359 */ 95 L4 = 2.222219843214978396e-01 /* 3FCC71C5 1D8E78AF */ 96 L5 = 1.818357216161805012e-01 /* 3FC74664 96CB03DE */ 97 L6 = 1.531383769920937332e-01 /* 3FC39A09 D078C69F */ 98 L7 = 1.479819860511658591e-01 /* 3FC2F112 DF3E5244 */ 99 ) 100 101 // special cases 102 switch { 103 case IsNaN(x) || IsInf(x, 1): 104 return x 105 case x < 0: 106 return NaN() 107 case x == 0: 108 return Inf(-1) 109 } 110 111 // reduce 112 f1, ki := Frexp(x) 113 if f1 < Sqrt2/2 { 114 f1 *= 2 115 ki-- 116 } 117 f := f1 - 1 118 k := float64(ki) 119 120 // compute 121 s := f / (2 + f) 122 s2 := s * s 123 s4 := s2 * s2 124 t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7))) 125 t2 := s4 * (L2 + s4*(L4+s4*L6)) 126 R := t1 + t2 127 hfsq := 0.5 * f * f 128 return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f) 129 }