github.com/gopherd/gonum@v0.0.4/diff/fd/derivative.go (about) 1 // Copyright ©2017 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 package fd 6 7 import ( 8 "math" 9 "runtime" 10 "sync" 11 ) 12 13 // Derivative estimates the derivative of the function f at the given location. 14 // The finite difference formula, the step size, and other options are 15 // specified by settings. If settings is nil, the first derivative will be 16 // estimated using the Forward formula and a default step size. 17 func Derivative(f func(float64) float64, x float64, settings *Settings) float64 { 18 // Default settings. 19 formula := Forward 20 step := formula.Step 21 var originValue float64 22 var originKnown, concurrent bool 23 24 // Use user settings if provided. 25 if settings != nil { 26 if !settings.Formula.isZero() { 27 formula = settings.Formula 28 step = formula.Step 29 checkFormula(formula) 30 } 31 if settings.Step != 0 { 32 step = settings.Step 33 } 34 originKnown = settings.OriginKnown 35 originValue = settings.OriginValue 36 concurrent = settings.Concurrent 37 } 38 39 var deriv float64 40 if !concurrent || runtime.GOMAXPROCS(0) == 1 { 41 for _, pt := range formula.Stencil { 42 if originKnown && pt.Loc == 0 { 43 deriv += pt.Coeff * originValue 44 continue 45 } 46 deriv += pt.Coeff * f(x+step*pt.Loc) 47 } 48 return deriv / math.Pow(step, float64(formula.Derivative)) 49 } 50 51 wg := &sync.WaitGroup{} 52 mux := &sync.Mutex{} 53 for _, pt := range formula.Stencil { 54 if originKnown && pt.Loc == 0 { 55 mux.Lock() 56 deriv += pt.Coeff * originValue 57 mux.Unlock() 58 continue 59 } 60 wg.Add(1) 61 go func(pt Point) { 62 defer wg.Done() 63 fofx := f(x + step*pt.Loc) 64 mux.Lock() 65 defer mux.Unlock() 66 deriv += pt.Coeff * fofx 67 }(pt) 68 } 69 wg.Wait() 70 return deriv / math.Pow(step, float64(formula.Derivative)) 71 }