...

Source file src/math/log.go

Documentation: math

		 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  //	Log(+Inf) = +Inf
		77  //	Log(0) = -Inf
		78  //	Log(x < 0) = NaN
		79  //	Log(NaN) = NaN
		80  func Log(x float64) float64 {
		81  	if haveArchLog {
		82  		return archLog(x)
		83  	}
		84  	return log(x)
		85  }
		86  
		87  func log(x float64) float64 {
		88  	const (
		89  		Ln2Hi = 6.93147180369123816490e-01 /* 3fe62e42 fee00000 */
		90  		Ln2Lo = 1.90821492927058770002e-10 /* 3dea39ef 35793c76 */
		91  		L1		= 6.666666666666735130e-01	 /* 3FE55555 55555593 */
		92  		L2		= 3.999999999940941908e-01	 /* 3FD99999 9997FA04 */
		93  		L3		= 2.857142874366239149e-01	 /* 3FD24924 94229359 */
		94  		L4		= 2.222219843214978396e-01	 /* 3FCC71C5 1D8E78AF */
		95  		L5		= 1.818357216161805012e-01	 /* 3FC74664 96CB03DE */
		96  		L6		= 1.531383769920937332e-01	 /* 3FC39A09 D078C69F */
		97  		L7		= 1.479819860511658591e-01	 /* 3FC2F112 DF3E5244 */
		98  	)
		99  
	 100  	// special cases
	 101  	switch {
	 102  	case IsNaN(x) || IsInf(x, 1):
	 103  		return x
	 104  	case x < 0:
	 105  		return NaN()
	 106  	case x == 0:
	 107  		return Inf(-1)
	 108  	}
	 109  
	 110  	// reduce
	 111  	f1, ki := Frexp(x)
	 112  	if f1 < Sqrt2/2 {
	 113  		f1 *= 2
	 114  		ki--
	 115  	}
	 116  	f := f1 - 1
	 117  	k := float64(ki)
	 118  
	 119  	// compute
	 120  	s := f / (2 + f)
	 121  	s2 := s * s
	 122  	s4 := s2 * s2
	 123  	t1 := s2 * (L1 + s4*(L3+s4*(L5+s4*L7)))
	 124  	t2 := s4 * (L2 + s4*(L4+s4*L6))
	 125  	R := t1 + t2
	 126  	hfsq := 0.5 * f * f
	 127  	return k*Ln2Hi - ((hfsq - (s*(hfsq+R) + k*Ln2Lo)) - f)
	 128  }
	 129  

View as plain text