gonum.org/v1/gonum@v0.14.0/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  //
    37  //	PowReal(NaN+xϵ, ±0) = 1+NaNϵ for any x
    38  //	PowReal(x, ±0) = 1 for any x
    39  //	PowReal(1+xϵ, y) = 1+xyϵ for any y
    40  //	PowReal(x, 1) = x for any x
    41  //	PowReal(NaN+xϵ, y) = NaN+NaNϵ
    42  //	PowReal(x, NaN) = NaN+NaNϵ
    43  //	PowReal(±0, y) = ±Inf for y an odd integer < 0
    44  //	PowReal(±0, -Inf) = +Inf
    45  //	PowReal(±0, +Inf) = +0
    46  //	PowReal(±0, y) = +Inf for finite y < 0 and not an odd integer
    47  //	PowReal(±0, y) = ±0 for y an odd integer > 0
    48  //	PowReal(±0, y) = +0 for finite y > 0 and not an odd integer
    49  //	PowReal(-1, ±Inf) = 1
    50  //	PowReal(x+0ϵ, +Inf) = +Inf+NaNϵ for |x| > 1
    51  //	PowReal(x+yϵ, +Inf) = +Inf for |x| > 1
    52  //	PowReal(x, -Inf) = +0+NaNϵ for |x| > 1
    53  //	PowReal(x, +Inf) = +0+NaNϵ for |x| < 1
    54  //	PowReal(x+0ϵ, -Inf) = +Inf+NaNϵ for |x| < 1
    55  //	PowReal(x, -Inf) = +Inf-Infϵ for |x| < 1
    56  //	PowReal(+Inf, y) = +Inf for y > 0
    57  //	PowReal(+Inf, y) = +0 for y < 0
    58  //	PowReal(-Inf, y) = Pow(-0, -y)
    59  //	PowReal(x, y) = NaN+NaNϵ for finite x < 0 and finite non-integer y
    60  func PowReal(d Number, p float64) Number {
    61  	const tol = 1e-15
    62  
    63  	r := d.Real
    64  	if math.Abs(r) < tol {
    65  		if r >= 0 {
    66  			r = tol
    67  		}
    68  		if r < 0 {
    69  			r = -tol
    70  		}
    71  	}
    72  	deriv := p * math.Pow(r, p-1)
    73  	return Number{
    74  		Real: math.Pow(d.Real, p),
    75  		Emag: d.Emag * deriv,
    76  	}
    77  }
    78  
    79  // Pow returns d**r, the base-d exponential of r.
    80  func Pow(d, p Number) Number {
    81  	return Exp(Mul(p, Log(d)))
    82  }
    83  
    84  // Sqrt returns the square root of d.
    85  //
    86  // Special cases are:
    87  //
    88  //	Sqrt(+Inf) = +Inf
    89  //	Sqrt(±0) = (±0+Infϵ)
    90  //	Sqrt(x < 0) = NaN
    91  //	Sqrt(NaN) = NaN
    92  func Sqrt(d Number) Number {
    93  	if d.Real <= 0 {
    94  		if d.Real == 0 {
    95  			return Number{
    96  				Real: d.Real,
    97  				Emag: math.Inf(1),
    98  			}
    99  		}
   100  		return Number{
   101  			Real: math.NaN(),
   102  			Emag: math.NaN(),
   103  		}
   104  	}
   105  	return PowReal(d, 0.5)
   106  }
   107  
   108  // Exp returns e**q, the base-e exponential of d.
   109  //
   110  // Special cases are:
   111  //
   112  //	Exp(+Inf) = +Inf
   113  //	Exp(NaN) = NaN
   114  //
   115  // Very large values overflow to 0 or +Inf.
   116  // Very small values underflow to 1.
   117  func Exp(d Number) Number {
   118  	fnDeriv := math.Exp(d.Real)
   119  	return Number{
   120  		Real: fnDeriv,
   121  		Emag: fnDeriv * d.Emag,
   122  	}
   123  }
   124  
   125  // Log returns the natural logarithm of d.
   126  //
   127  // Special cases are:
   128  //
   129  //	Log(+Inf) = (+Inf+0ϵ)
   130  //	Log(0) = (-Inf±Infϵ)
   131  //	Log(x < 0) = NaN
   132  //	Log(NaN) = NaN
   133  func Log(d Number) Number {
   134  	switch d.Real {
   135  	case 0:
   136  		return Number{
   137  			Real: math.Log(d.Real),
   138  			Emag: math.Copysign(math.Inf(1), d.Real),
   139  		}
   140  	case math.Inf(1):
   141  		return Number{
   142  			Real: math.Log(d.Real),
   143  			Emag: 0,
   144  		}
   145  	}
   146  	if d.Real < 0 {
   147  		return Number{
   148  			Real: math.NaN(),
   149  			Emag: math.NaN(),
   150  		}
   151  	}
   152  	return Number{
   153  		Real: math.Log(d.Real),
   154  		Emag: d.Emag / d.Real,
   155  	}
   156  }
   157  
   158  // Sin returns the sine of d.
   159  //
   160  // Special cases are:
   161  //
   162  //	Sin(±0) = (±0+Nϵ)
   163  //	Sin(±Inf) = NaN
   164  //	Sin(NaN) = NaN
   165  func Sin(d Number) Number {
   166  	if d.Real == 0 {
   167  		return Number{
   168  			Real: d.Real,
   169  			Emag: d.Emag,
   170  		}
   171  	}
   172  	fn := math.Sin(d.Real)
   173  	deriv := math.Cos(d.Real)
   174  	return Number{
   175  		Real: fn,
   176  		Emag: deriv * d.Emag,
   177  	}
   178  }
   179  
   180  // Cos returns the cosine of d.
   181  //
   182  // Special cases are:
   183  //
   184  //	Cos(±Inf) = NaN
   185  //	Cos(NaN) = NaN
   186  func Cos(d Number) Number {
   187  	fn := math.Cos(d.Real)
   188  	deriv := -math.Sin(d.Real)
   189  	return Number{
   190  		Real: fn,
   191  		Emag: deriv * d.Emag,
   192  	}
   193  }
   194  
   195  // Tan returns the tangent of d.
   196  //
   197  // Special cases are:
   198  //
   199  //	Tan(±0) = (±0+Nϵ)
   200  //	Tan(±Inf) = NaN
   201  //	Tan(NaN) = NaN
   202  func Tan(d Number) Number {
   203  	if d.Real == 0 {
   204  		return Number{
   205  			Real: d.Real,
   206  			Emag: d.Emag,
   207  		}
   208  	}
   209  	fn := math.Tan(d.Real)
   210  	deriv := 1 + fn*fn
   211  	return Number{
   212  		Real: fn,
   213  		Emag: deriv * d.Emag,
   214  	}
   215  }
   216  
   217  // Asin returns the inverse sine of d.
   218  //
   219  // Special cases are:
   220  //
   221  //	Asin(±0) = (±0+Nϵ)
   222  //	Asin(±1) = (±Inf+Infϵ)
   223  //	Asin(x) = NaN if x < -1 or x > 1
   224  func Asin(d Number) Number {
   225  	if d.Real == 0 {
   226  		return Number{
   227  			Real: d.Real,
   228  			Emag: d.Emag,
   229  		}
   230  	} else if m := math.Abs(d.Real); m >= 1 {
   231  		if m == 1 {
   232  			return Number{
   233  				Real: math.Asin(d.Real),
   234  				Emag: math.Inf(1),
   235  			}
   236  		}
   237  		return Number{
   238  			Real: math.NaN(),
   239  			Emag: math.NaN(),
   240  		}
   241  	}
   242  	fn := math.Asin(d.Real)
   243  	deriv := 1 / math.Sqrt(1-d.Real*d.Real)
   244  	return Number{
   245  		Real: fn,
   246  		Emag: deriv * d.Emag,
   247  	}
   248  }
   249  
   250  // Acos returns the inverse cosine of d.
   251  //
   252  // Special cases are:
   253  //
   254  //	Acos(-1) = (Pi-Infϵ)
   255  //	Acos(1) = (0-Infϵ)
   256  //	Acos(x) = NaN if x < -1 or x > 1
   257  func Acos(d Number) Number {
   258  	if m := math.Abs(d.Real); m >= 1 {
   259  		if m == 1 {
   260  			return Number{
   261  				Real: math.Acos(d.Real),
   262  				Emag: math.Inf(-1),
   263  			}
   264  		}
   265  		return Number{
   266  			Real: math.NaN(),
   267  			Emag: math.NaN(),
   268  		}
   269  	}
   270  	fn := math.Acos(d.Real)
   271  	deriv := -1 / math.Sqrt(1-d.Real*d.Real)
   272  	return Number{
   273  		Real: fn,
   274  		Emag: deriv * d.Emag,
   275  	}
   276  }
   277  
   278  // Atan returns the inverse tangent of d.
   279  //
   280  // Special cases are:
   281  //
   282  //	Atan(±0) = (±0+Nϵ)
   283  //	Atan(±Inf) = (±Pi/2+0ϵ)
   284  func Atan(d Number) Number {
   285  	if d.Real == 0 {
   286  		return Number{
   287  			Real: d.Real,
   288  			Emag: d.Emag,
   289  		}
   290  	}
   291  	fn := math.Atan(d.Real)
   292  	deriv := 1 / (1 + d.Real*d.Real)
   293  	return Number{
   294  		Real: fn,
   295  		Emag: deriv * d.Emag,
   296  	}
   297  }