...

Source file src/math/log1p.go

Documentation: math

		 1  // Copyright 2010 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  // The original C code, the long comment, and the constants
		 8  // below are from FreeBSD's /usr/src/lib/msun/src/s_log1p.c
		 9  // and came with this notice. The go code is a simplified
		10  // version of the original C.
		11  //
		12  // ====================================================
		13  // Copyright (C) 1993 by Sun Microsystems, Inc. All rights reserved.
		14  //
		15  // Developed at SunPro, a Sun Microsystems, Inc. business.
		16  // Permission to use, copy, modify, and distribute this
		17  // software is freely granted, provided that this notice
		18  // is preserved.
		19  // ====================================================
		20  //
		21  //
		22  // double log1p(double x)
		23  //
		24  // Method :
		25  //	 1. Argument Reduction: find k and f such that
		26  //											1+x = 2**k * (1+f),
		27  //				 where	sqrt(2)/2 < 1+f < sqrt(2) .
		28  //
		29  //			Note. If k=0, then f=x is exact. However, if k!=0, then f
		30  //			may not be representable exactly. In that case, a correction
		31  //			term is need. Let u=1+x rounded. Let c = (1+x)-u, then
		32  //			log(1+x) - log(u) ~ c/u. Thus, we proceed to compute log(u),
		33  //			and add back the correction term c/u.
		34  //			(Note: when x > 2**53, one can simply return log(x))
		35  //
		36  //	 2. Approximation of log1p(f).
		37  //			Let s = f/(2+f) ; based on log(1+f) = log(1+s) - log(1-s)
		38  //							 = 2s + 2/3 s**3 + 2/5 s**5 + .....,
		39  //							 = 2s + s*R
		40  //			We use a special Reme algorithm on [0,0.1716] to generate
		41  //			a polynomial of degree 14 to approximate R The maximum error
		42  //			of this polynomial approximation is bounded by 2**-58.45. In
		43  //			other words,
		44  //											2			4			6			8			10			12			14
		45  //					R(z) ~ Lp1*s +Lp2*s +Lp3*s +Lp4*s +Lp5*s	+Lp6*s	+Lp7*s
		46  //			(the values of Lp1 to Lp7 are listed in the program)
		47  //			and
		48  //					|			2					14					|		 -58.45
		49  //					| Lp1*s +...+Lp7*s		-	R(z) | <= 2
		50  //					|														 |
		51  //			Note that 2s = f - s*f = f - hfsq + s*hfsq, where hfsq = f*f/2.
		52  //			In order to guarantee error in log below 1ulp, we compute log
		53  //			by
		54  //							log1p(f) = f - (hfsq - s*(hfsq+R)).
		55  //
		56  //	 3. Finally, log1p(x) = k*ln2 + log1p(f).
		57  //												= k*ln2_hi+(f-(hfsq-(s*(hfsq+R)+k*ln2_lo)))
		58  //			Here ln2 is split into two floating point number:
		59  //									 ln2_hi + ln2_lo,
		60  //			where n*ln2_hi is always exact for |n| < 2000.
		61  //
		62  // Special cases:
		63  //			log1p(x) is NaN with signal if x < -1 (including -INF) ;
		64  //			log1p(+INF) is +INF; log1p(-1) is -INF with signal;
		65  //			log1p(NaN) is that NaN with no signal.
		66  //
		67  // Accuracy:
		68  //			according to an error analysis, the error is always less than
		69  //			1 ulp (unit in the last place).
		70  //
		71  // Constants:
		72  // The hexadecimal values are the intended ones for the following
		73  // constants. The decimal values may be used, provided that the
		74  // compiler will convert from decimal to binary accurately enough
		75  // to produce the hexadecimal values shown.
		76  //
		77  // Note: Assuming log() return accurate answer, the following
		78  //			 algorithm can be used to compute log1p(x) to within a few ULP:
		79  //
		80  //							u = 1+x;
		81  //							if(u==1.0) return x ; else
		82  //												 return log(u)*(x/(u-1.0));
		83  //
		84  //			 See HP-15C Advanced Functions Handbook, p.193.
		85  
		86  // Log1p returns the natural logarithm of 1 plus its argument x.
		87  // It is more accurate than Log(1 + x) when x is near zero.
		88  //
		89  // Special cases are:
		90  //	Log1p(+Inf) = +Inf
		91  //	Log1p(±0) = ±0
		92  //	Log1p(-1) = -Inf
		93  //	Log1p(x < -1) = NaN
		94  //	Log1p(NaN) = NaN
		95  func Log1p(x float64) float64 {
		96  	if haveArchLog1p {
		97  		return archLog1p(x)
		98  	}
		99  	return log1p(x)
	 100  }
	 101  
	 102  func log1p(x float64) float64 {
	 103  	const (
	 104  		Sqrt2M1		 = 4.142135623730950488017e-01	// Sqrt(2)-1 = 0x3fda827999fcef34
	 105  		Sqrt2HalfM1 = -2.928932188134524755992e-01 // Sqrt(2)/2-1 = 0xbfd2bec333018866
	 106  		Small			 = 1.0 / (1 << 29)							// 2**-29 = 0x3e20000000000000
	 107  		Tiny				= 1.0 / (1 << 54)							// 2**-54
	 108  		Two53			 = 1 << 53											// 2**53
	 109  		Ln2Hi			 = 6.93147180369123816490e-01	 // 3fe62e42fee00000
	 110  		Ln2Lo			 = 1.90821492927058770002e-10	 // 3dea39ef35793c76
	 111  		Lp1				 = 6.666666666666735130e-01		 // 3FE5555555555593
	 112  		Lp2				 = 3.999999999940941908e-01		 // 3FD999999997FA04
	 113  		Lp3				 = 2.857142874366239149e-01		 // 3FD2492494229359
	 114  		Lp4				 = 2.222219843214978396e-01		 // 3FCC71C51D8E78AF
	 115  		Lp5				 = 1.818357216161805012e-01		 // 3FC7466496CB03DE
	 116  		Lp6				 = 1.531383769920937332e-01		 // 3FC39A09D078C69F
	 117  		Lp7				 = 1.479819860511658591e-01		 // 3FC2F112DF3E5244
	 118  	)
	 119  
	 120  	// special cases
	 121  	switch {
	 122  	case x < -1 || IsNaN(x): // includes -Inf
	 123  		return NaN()
	 124  	case x == -1:
	 125  		return Inf(-1)
	 126  	case IsInf(x, 1):
	 127  		return Inf(1)
	 128  	}
	 129  
	 130  	absx := Abs(x)
	 131  
	 132  	var f float64
	 133  	var iu uint64
	 134  	k := 1
	 135  	if absx < Sqrt2M1 { //	|x| < Sqrt(2)-1
	 136  		if absx < Small { // |x| < 2**-29
	 137  			if absx < Tiny { // |x| < 2**-54
	 138  				return x
	 139  			}
	 140  			return x - x*x*0.5
	 141  		}
	 142  		if x > Sqrt2HalfM1 { // Sqrt(2)/2-1 < x
	 143  			// (Sqrt(2)/2-1) < x < (Sqrt(2)-1)
	 144  			k = 0
	 145  			f = x
	 146  			iu = 1
	 147  		}
	 148  	}
	 149  	var c float64
	 150  	if k != 0 {
	 151  		var u float64
	 152  		if absx < Two53 { // 1<<53
	 153  			u = 1.0 + x
	 154  			iu = Float64bits(u)
	 155  			k = int((iu >> 52) - 1023)
	 156  			// correction term
	 157  			if k > 0 {
	 158  				c = 1.0 - (u - x)
	 159  			} else {
	 160  				c = x - (u - 1.0)
	 161  			}
	 162  			c /= u
	 163  		} else {
	 164  			u = x
	 165  			iu = Float64bits(u)
	 166  			k = int((iu >> 52) - 1023)
	 167  			c = 0
	 168  		}
	 169  		iu &= 0x000fffffffffffff
	 170  		if iu < 0x0006a09e667f3bcd { // mantissa of Sqrt(2)
	 171  			u = Float64frombits(iu | 0x3ff0000000000000) // normalize u
	 172  		} else {
	 173  			k++
	 174  			u = Float64frombits(iu | 0x3fe0000000000000) // normalize u/2
	 175  			iu = (0x0010000000000000 - iu) >> 2
	 176  		}
	 177  		f = u - 1.0 // Sqrt(2)/2 < u < Sqrt(2)
	 178  	}
	 179  	hfsq := 0.5 * f * f
	 180  	var s, R, z float64
	 181  	if iu == 0 { // |f| < 2**-20
	 182  		if f == 0 {
	 183  			if k == 0 {
	 184  				return 0
	 185  			}
	 186  			c += float64(k) * Ln2Lo
	 187  			return float64(k)*Ln2Hi + c
	 188  		}
	 189  		R = hfsq * (1.0 - 0.66666666666666666*f) // avoid division
	 190  		if k == 0 {
	 191  			return f - R
	 192  		}
	 193  		return float64(k)*Ln2Hi - ((R - (float64(k)*Ln2Lo + c)) - f)
	 194  	}
	 195  	s = f / (2.0 + f)
	 196  	z = s * s
	 197  	R = z * (Lp1 + z*(Lp2+z*(Lp3+z*(Lp4+z*(Lp5+z*(Lp6+z*Lp7))))))
	 198  	if k == 0 {
	 199  		return f - (hfsq - s*(hfsq+R))
	 200  	}
	 201  	return float64(k)*Ln2Hi - ((hfsq - (s*(hfsq+R) + (float64(k)*Ln2Lo + c))) - f)
	 202  }
	 203  

View as plain text