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 }