blob: e5aa9af31d0ab2f1415f59d7724a4f6e5f684785 [file] [log] [blame]
// Copyright ©2017 The gonum Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
package fd
import (
"math"
"runtime"
"sync"
)
// Derivative estimates the derivative of the function f at the given location.
// The finite difference formula, the step size, and other options are
// specified by settings. If settings is nil, the first derivative will be
// estimated using the Forward formula and a default step size.
func Derivative(f func(float64) float64, x float64, settings *Settings) float64 {
// Default settings.
formula := Forward
step := formula.Step
var originValue float64
var originKnown, concurrent bool
// Use user settings if provided.
if settings != nil {
if !settings.Formula.isZero() {
formula = settings.Formula
step = formula.Step
checkFormula(formula)
}
if settings.Step != 0 {
step = settings.Step
}
originKnown = settings.OriginKnown
originValue = settings.OriginValue
concurrent = settings.Concurrent
}
var deriv float64
if !concurrent || runtime.GOMAXPROCS(0) == 1 {
for _, pt := range formula.Stencil {
if originKnown && pt.Loc == 0 {
deriv += pt.Coeff * originValue
continue
}
deriv += pt.Coeff * f(x+step*pt.Loc)
}
return deriv / math.Pow(step, float64(formula.Derivative))
}
wg := &sync.WaitGroup{}
mux := &sync.Mutex{}
for _, pt := range formula.Stencil {
if originKnown && pt.Loc == 0 {
mux.Lock()
deriv += pt.Coeff * originValue
mux.Unlock()
continue
}
wg.Add(1)
go func(pt Point) {
defer wg.Done()
fofx := f(x + step*pt.Loc)
mux.Lock()
defer mux.Unlock()
deriv += pt.Coeff * fofx
}(pt)
}
wg.Wait()
return deriv / math.Pow(step, float64(formula.Derivative))
}