gitee.com/quant1x/num@v0.3.2/math32/expm1f.go (about)

     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 math32
     6  
     7  // The original C code, the long comment, and the constants
     8  // below are from FreeBSD's /usr/src/lib/msun/src/s_expm1.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  // expm1(x)
    22  // Returns exp(x)-1, the exponential of x minus 1.
    23  //
    24  // Method
    25  //   1. Argument reduction:
    26  //      Given x, find r and integer k such that
    27  //
    28  //               x = k*ln2 + r,  |r| <= 0.5*ln2 ~ 0.34658
    29  //
    30  //      Here a correction term c will be computed to compensate
    31  //      the error in r when rounded to a floating-point number.
    32  //
    33  //   2. Approximating expm1(r) by a special rational function on
    34  //      the interval [0,0.34658]:
    35  //      Since
    36  //          r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 - r**4/360 + ...
    37  //      we define R1(r*r) by
    38  //          r*(exp(r)+1)/(exp(r)-1) = 2+ r**2/6 * R1(r*r)
    39  //      That is,
    40  //          R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r)
    41  //                   = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r))
    42  //                   = 1 - r**2/60 + r**4/2520 - r**6/100800 + ...
    43  //      We use a special Reme algorithm on [0,0.347] to generate
    44  //      a polynomial of degree 5 in r*r to approximate R1. The
    45  //      maximum error of this polynomial approximation is bounded
    46  //      by 2**-61. In other words,
    47  //          R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5
    48  //      where   Q1  =  -1.6666666666666567384E-2,
    49  //              Q2  =   3.9682539681370365873E-4,
    50  //              Q3  =  -9.9206344733435987357E-6,
    51  //              Q4  =   2.5051361420808517002E-7,
    52  //              Q5  =  -6.2843505682382617102E-9;
    53  //      (where z=r*r, and the values of Q1 to Q5 are listed below)
    54  //      with error bounded by
    55  //          |                  5           |     -61
    56  //          | 1.0+Q1*z+...+Q5*z   -  R1(z) | <= 2
    57  //          |                              |
    58  //
    59  //      expm1(r) = exp(r)-1 is then computed by the following
    60  //      specific way which minimize the accumulation rounding error:
    61  //                             2     3
    62  //                            r     r    [ 3 - (R1 + R1*r/2)  ]
    63  //            expm1(r) = r + --- + --- * [--------------------]
    64  //                            2     2    [ 6 - r*(3 - R1*r/2) ]
    65  //
    66  //      To compensate the error in the argument reduction, we use
    67  //              expm1(r+c) = expm1(r) + c + expm1(r)*c
    68  //                         ~ expm1(r) + c + r*c
    69  //      Thus c+r*c will be added in as the correction terms for
    70  //      expm1(r+c). Now rearrange the term to avoid optimization
    71  //      screw up:
    72  //                      (      2                                    2 )
    73  //                      ({  ( r    [ R1 -  (3 - R1*r/2) ]  )  }    r  )
    74  //       expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- )
    75  //                      ({  ( 2    [ 6 - r*(3 - R1*r/2) ]  )  }    2  )
    76  //                      (                                             )
    77  //
    78  //                 = r - E
    79  //   3. Scale back to obtain expm1(x):
    80  //      From step 1, we have
    81  //         expm1(x) = either 2**k*[expm1(r)+1] - 1
    82  //                  = or     2**k*[expm1(r) + (1-2**-k)]
    83  //   4. Implementation notes:
    84  //      (A). To save one multiplication, we scale the coefficient Qi
    85  //           to Qi*2**i, and replace z by (x**2)/2.
    86  //      (B). To achieve maximum accuracy, we compute expm1(x) by
    87  //        (i)   if x < -56*ln2, return -1.0, (raise inexact if x!=inf)
    88  //        (ii)  if k=0, return r-E
    89  //        (iii) if k=-1, return 0.5*(r-E)-0.5
    90  //        (iv)  if k=1 if r < -0.25, return 2*((r+0.5)- E)
    91  //                     else          return  1.0+2.0*(r-E);
    92  //        (v)   if (k<-2||k>56) return 2**k(1-(E-r)) - 1 (or exp(x)-1)
    93  //        (vi)  if k <= 20, return 2**k((1-2**-k)-(E-r)), else
    94  //        (vii) return 2**k(1-((E+2**-k)-r))
    95  //
    96  // Special cases:
    97  //      expm1(INF) is INF, expm1(NaN) is NaN;
    98  //      expm1(-INF) is -1, and
    99  //      for finite argument, only expm1(0)=0 is exact.
   100  //
   101  // Accuracy:
   102  //      according to an error analysis, the error is always less than
   103  //      1 ulp (unit in the last place).
   104  //
   105  // Misc. info.
   106  //      For IEEE double
   107  //          if x >  7.09782712893383973096e+02 then expm1(x) overflow
   108  //
   109  // Constants:
   110  // The hexadecimal values are the intended ones for the following
   111  // constants. The decimal values may be used, provided that the
   112  // compiler will convert from decimal to binary accurately enough
   113  // to produce the hexadecimal values shown.
   114  //
   115  
   116  // Expm1 returns e**x - 1, the base-e exponential of x minus 1.
   117  // It is more accurate than Exp(x) - 1 when x is near zero.
   118  //
   119  // Special cases are:
   120  //
   121  //	Expm1(+Inf) = +Inf
   122  //	Expm1(-Inf) = -1
   123  //	Expm1(NaN) = NaN
   124  //
   125  // Very large values overflow to -1 or +Inf.
   126  func Expm1(x float32) float32 {
   127  	return expm1(x)
   128  }
   129  
   130  func expm1(x float32) float32 {
   131  	const (
   132  		Othreshold = 89.415985                   // 0x42b2d4fc
   133  		Ln2X27     = 1.871497344970703125e+01    // 0x4195b844
   134  		Ln2HalfX3  = 1.0397207736968994140625    // 0x3F851592
   135  		Ln2Half    = 3.465735912322998046875e-01 // 0x3eb17218
   136  		Ln2Hi      = 6.9313812256e-01            // 0x3f317180
   137  		Ln2Lo      = 9.0580006145e-06            // 0x3717f7d1
   138  		InvLn2     = 1.4426950216e+00            // 0x3fb8aa3b
   139  		Tiny       = 1.0 / (1 << 54)             // 2**-54 = 0x3c90000000000000
   140  
   141  		/* scaled coefficients related to expm1 */
   142  		Q1 = -3.3333335072e-02 /* 0xbd088889 */
   143  		Q2 = 1.5873016091e-03  /* 0x3ad00d01 */
   144  		Q3 = -7.9365076090e-05 /* 0xb8a670cd */
   145  		Q4 = 4.0082177293e-06  /* 0x36867e54 */
   146  		Q5 = -2.0109921195e-07 /* 0xb457edbb */
   147  	)
   148  
   149  	// special cases
   150  	switch {
   151  	case IsInf(x, 1) || IsNaN(x):
   152  		return x
   153  	case IsInf(x, -1):
   154  		return -1
   155  	}
   156  
   157  	absx := x
   158  	sign := false
   159  	if x < 0 {
   160  		absx = -absx
   161  		sign = true
   162  	}
   163  
   164  	// filter out huge argument
   165  	if absx >= Ln2X27 { // if |x| >= 27 * ln2
   166  		if sign {
   167  			return -1 // x < -56*ln2, return -1
   168  		}
   169  		if absx >= Othreshold { // if |x| >= 89.415985...
   170  			return Inf(1)
   171  		}
   172  	}
   173  
   174  	// argument reduction
   175  	var c float32
   176  	var k int
   177  	if absx > Ln2Half { // if  |x| > 0.5 * ln2
   178  		var hi, lo float32
   179  		if absx < Ln2HalfX3 { // and |x| < 1.5 * ln2
   180  			if !sign {
   181  				hi = x - Ln2Hi
   182  				lo = Ln2Lo
   183  				k = 1
   184  			} else {
   185  				hi = x + Ln2Hi
   186  				lo = -Ln2Lo
   187  				k = -1
   188  			}
   189  		} else {
   190  			if !sign {
   191  				k = int(InvLn2*x + 0.5)
   192  			} else {
   193  				k = int(InvLn2*x - 0.5)
   194  			}
   195  			t := float32(k)
   196  			hi = x - t*Ln2Hi // t * Ln2Hi is exact here
   197  			lo = t * Ln2Lo
   198  		}
   199  		x = hi - lo
   200  		c = (hi - x) - lo
   201  	} else if absx < Tiny { // when |x| < 2**-54, return x
   202  		return x
   203  	} else {
   204  		k = 0
   205  	}
   206  
   207  	// x is now in primary range
   208  	hfx := 0.5 * x
   209  	hxs := x * hfx
   210  	r1 := 1 + hxs*(Q1+hxs*(Q2+hxs*(Q3+hxs*(Q4+hxs*Q5))))
   211  	t := 3 - r1*hfx
   212  	e := hxs * ((r1 - t) / (6.0 - x*t))
   213  	if k != 0 {
   214  		e = (x*(e-c) - c)
   215  		e -= hxs
   216  		switch {
   217  		case k == -1:
   218  			return 0.5*(x-e) - 0.5
   219  		case k == 1:
   220  			if x < -0.25 {
   221  				return -2 * (e - (x + 0.5))
   222  			}
   223  			return 1 + 2*(x-e)
   224  		case k <= -2 || k > 56: // suffice to return exp(x)-1
   225  			y := 1 - (e - x)
   226  			y = Float32frombits(Float32bits(y) + uint32(k)<<23) // add k to y's exponent
   227  			return y - 1
   228  		}
   229  		if k < 20 {
   230  			t := Float32frombits(0x3f800000 - (0x1000000 >> uint(k))) // t=1-2**-k
   231  			y := t - (e - x)
   232  			y = Float32frombits(Float32bits(y) + uint32(k)<<23) // add k to y's exponent
   233  			return y
   234  		}
   235  		t := Float32frombits(uint32(0x7f-k) << 23) // 2**-k
   236  		y := x - (e + t)
   237  		y += 1
   238  		y = Float32frombits(Float32bits(y) + uint32(k)<<23) // add k to y's exponent
   239  		return y
   240  	}
   241  	return x - (x*e - hxs) // c is 0
   242  }