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 }