github.com/jingcheng-WU/gonum@v0.9.1-0.20210323123734-f1a2a11a8f7b/num/dual/dual_fike.go (about)

     1  // Copyright ©2018 The Gonum 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  // Derived from code by Jeffrey A. Fike at http://adl.stanford.edu/hyperdual/
     6  
     7  // The MIT License (MIT)
     8  //
     9  // Copyright (c) 2006 Jeffrey A. Fike
    10  //
    11  // Permission is hereby granted, free of charge, to any person obtaining a copy
    12  // of this software and associated documentation files (the "Software"), to deal
    13  // in the Software without restriction, including without limitation the rights
    14  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    15  // copies of the Software, and to permit persons to whom the Software is
    16  // furnished to do so, subject to the following conditions:
    17  //
    18  // The above copyright notice and this permission notice shall be included in
    19  // all copies or substantial portions of the Software.
    20  //
    21  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    22  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    23  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
    24  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    25  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    26  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    27  // THE SOFTWARE.
    28  
    29  package dual
    30  
    31  import "math"
    32  
    33  // PowReal returns x**p, the base-x exponential of p.
    34  //
    35  // Special cases are (in order):
    36  //	PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x
    37  //	PowReal(x, ±0) = 1 for any x
    38  //	PowReal(1+xϵ, y) = 1+xyϵ for any y
    39  //	PowReal(x, 1) = x for any x
    40  //	PowReal(NaN+xϵ, y) = NaN+NaNϵ
    41  //	PowReal(x, NaN) = NaN+NaNϵ
    42  //	PowReal(±0, y) = ±Inf for y an odd integer < 0
    43  //	PowReal(±0, -Inf) = +Inf
    44  //	PowReal(±0, +Inf) = +0
    45  //	PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer
    46  //	PowReal(±0, y) = ±0 for y an odd integer > 0
    47  //	PowReal(±0, y) = +0 for finite y > 0 and not an odd integer
    48  //	PowReal(-1, ±Inf) = 1
    49  //	PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1
    50  //	PowReal(x+yϵ, +Inf) = +Inf for |x| > 1
    51  //	PowReal(x, -Inf) = +0+NaNϵ for |x| > 1
    52  //	PowReal(x, +Inf) = +0+NaNϵ for |x| < 1
    53  //	PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1
    54  //	PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1
    55  //	PowReal(+Inf, y) = +Inf for y > 0
    56  //	PowReal(+Inf, y) = +0 for y < 0
    57  //	PowReal(-Inf, y) = Pow(-0, -y)
    58  //	PowReal(x, y) = NaN+NaNϵ for finite x < 0 and finite non-integer y
    59  func PowReal(d Number, p float64) Number {
    60  	const tol = 1e-15
    61  
    62  	r := d.Real
    63  	if math.Abs(r) < tol {
    64  		if r >= 0 {
    65  			r = tol
    66  		}
    67  		if r < 0 {
    68  			r = -tol
    69  		}
    70  	}
    71  	deriv := p * math.Pow(r, p-1)
    72  	return Number{
    73  		Real: math.Pow(d.Real, p),
    74  		Emag: d.Emag * deriv,
    75  	}
    76  }
    77  
    78  // Pow returns d**r, the base-d exponential of r.
    79  func Pow(d, p Number) Number {
    80  	return Exp(Mul(p, Log(d)))
    81  }
    82  
    83  // Sqrt returns the square root of d.
    84  //
    85  // Special cases are:
    86  //	Sqrt(+Inf) = +Inf
    87  //	Sqrt(±0) = (±0+Infϵ)
    88  //	Sqrt(x < 0) = NaN
    89  //	Sqrt(NaN) = NaN
    90  func Sqrt(d Number) Number {
    91  	if d.Real <= 0 {
    92  		if d.Real == 0 {
    93  			return Number{
    94  				Real: d.Real,
    95  				Emag: math.Inf(1),
    96  			}
    97  		}
    98  		return Number{
    99  			Real: math.NaN(),
   100  			Emag: math.NaN(),
   101  		}
   102  	}
   103  	return PowReal(d, 0.5)
   104  }
   105  
   106  // Exp returns e**q, the base-e exponential of d.
   107  //
   108  // Special cases are:
   109  //	Exp(+Inf) = +Inf
   110  //	Exp(NaN) = NaN
   111  // Very large values overflow to 0 or +Inf.
   112  // Very small values underflow to 1.
   113  func Exp(d Number) Number {
   114  	fnDeriv := math.Exp(d.Real)
   115  	return Number{
   116  		Real: fnDeriv,
   117  		Emag: fnDeriv * d.Emag,
   118  	}
   119  }
   120  
   121  // Log returns the natural logarithm of d.
   122  //
   123  // Special cases are:
   124  //	Log(+Inf) = (+Inf+0ϵ)
   125  //	Log(0) = (-Inf±Infϵ)
   126  //	Log(x < 0) = NaN
   127  //	Log(NaN) = NaN
   128  func Log(d Number) Number {
   129  	switch d.Real {
   130  	case 0:
   131  		return Number{
   132  			Real: math.Log(d.Real),
   133  			Emag: math.Copysign(math.Inf(1), d.Real),
   134  		}
   135  	case math.Inf(1):
   136  		return Number{
   137  			Real: math.Log(d.Real),
   138  			Emag: 0,
   139  		}
   140  	}
   141  	if d.Real < 0 {
   142  		return Number{
   143  			Real: math.NaN(),
   144  			Emag: math.NaN(),
   145  		}
   146  	}
   147  	return Number{
   148  		Real: math.Log(d.Real),
   149  		Emag: d.Emag / d.Real,
   150  	}
   151  }
   152  
   153  // Sin returns the sine of d.
   154  //
   155  // Special cases are:
   156  //	Sin(±0) = (±0+Nϵ)
   157  //	Sin(±Inf) = NaN
   158  //	Sin(NaN) = NaN
   159  func Sin(d Number) Number {
   160  	if d.Real == 0 {
   161  		return Number{
   162  			Real: d.Real,
   163  			Emag: d.Emag,
   164  		}
   165  	}
   166  	fn := math.Sin(d.Real)
   167  	deriv := math.Cos(d.Real)
   168  	return Number{
   169  		Real: fn,
   170  		Emag: deriv * d.Emag,
   171  	}
   172  }
   173  
   174  // Cos returns the cosine of d.
   175  //
   176  // Special cases are:
   177  //	Cos(±Inf) = NaN
   178  //	Cos(NaN) = NaN
   179  func Cos(d Number) Number {
   180  	fn := math.Cos(d.Real)
   181  	deriv := -math.Sin(d.Real)
   182  	return Number{
   183  		Real: fn,
   184  		Emag: deriv * d.Emag,
   185  	}
   186  }
   187  
   188  // Tan returns the tangent of d.
   189  //
   190  // Special cases are:
   191  //	Tan(±0) = (±0+Nϵ)
   192  //	Tan(±Inf) = NaN
   193  //	Tan(NaN) = NaN
   194  func Tan(d Number) Number {
   195  	if d.Real == 0 {
   196  		return Number{
   197  			Real: d.Real,
   198  			Emag: d.Emag,
   199  		}
   200  	}
   201  	fn := math.Tan(d.Real)
   202  	deriv := 1 + fn*fn
   203  	return Number{
   204  		Real: fn,
   205  		Emag: deriv * d.Emag,
   206  	}
   207  }
   208  
   209  // Asin returns the inverse sine of d.
   210  //
   211  // Special cases are:
   212  //	Asin(±0) = (±0+Nϵ)
   213  //	Asin(±1) = (±Inf+Infϵ)
   214  //	Asin(x) = NaN if x < -1 or x > 1
   215  func Asin(d Number) Number {
   216  	if d.Real == 0 {
   217  		return Number{
   218  			Real: d.Real,
   219  			Emag: d.Emag,
   220  		}
   221  	} else if m := math.Abs(d.Real); m >= 1 {
   222  		if m == 1 {
   223  			return Number{
   224  				Real: math.Asin(d.Real),
   225  				Emag: math.Inf(1),
   226  			}
   227  		}
   228  		return Number{
   229  			Real: math.NaN(),
   230  			Emag: math.NaN(),
   231  		}
   232  	}
   233  	fn := math.Asin(d.Real)
   234  	deriv := 1 / math.Sqrt(1-d.Real*d.Real)
   235  	return Number{
   236  		Real: fn,
   237  		Emag: deriv * d.Emag,
   238  	}
   239  }
   240  
   241  // Acos returns the inverse cosine of d.
   242  //
   243  // Special cases are:
   244  //	Acos(-1) = (Pi-Infϵ)
   245  //	Acos(1) = (0-Infϵ)
   246  //	Acos(x) = NaN if x < -1 or x > 1
   247  func Acos(d Number) Number {
   248  	if m := math.Abs(d.Real); m >= 1 {
   249  		if m == 1 {
   250  			return Number{
   251  				Real: math.Acos(d.Real),
   252  				Emag: math.Inf(-1),
   253  			}
   254  		}
   255  		return Number{
   256  			Real: math.NaN(),
   257  			Emag: math.NaN(),
   258  		}
   259  	}
   260  	fn := math.Acos(d.Real)
   261  	deriv := -1 / math.Sqrt(1-d.Real*d.Real)
   262  	return Number{
   263  		Real: fn,
   264  		Emag: deriv * d.Emag,
   265  	}
   266  }
   267  
   268  // Atan returns the inverse tangent of d.
   269  //
   270  // Special cases are:
   271  //	Atan(±0) = (±0+Nϵ)
   272  //	Atan(±Inf) = (±Pi/2+0ϵ)
   273  func Atan(d Number) Number {
   274  	if d.Real == 0 {
   275  		return Number{
   276  			Real: d.Real,
   277  			Emag: d.Emag,
   278  		}
   279  	}
   280  	fn := math.Atan(d.Real)
   281  	deriv := 1 / (1 + d.Real*d.Real)
   282  	return Number{
   283  		Real: fn,
   284  		Emag: deriv * d.Emag,
   285  	}
   286  }