用 C# 进行数学函数微分?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/373186/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mathematical function differentiation with C#?
提问by Rogez Sanchez
I see that I can declare a function with (say)
我看到我可以用(说)声明一个函数
public double Function(double parameter)
but what if I do want to take the derivative of that function?
但是如果我确实想取那个函数的导数呢?
回答by Chris Brandsma
Are you thinking of Lambda Expressions?
你在考虑 Lambda 表达式吗?
Basically you can pass a function into a function.
基本上你可以将一个函数传递给一个函数。
So think of a Sort on an object. Depending on the nature of the object would help determine how the objects are sorted.
因此,请考虑对对象进行排序。根据对象的性质将有助于确定对象的排序方式。
But you can still create a generic sort function then pass in how to compare objects.
但是您仍然可以创建一个通用的排序函数,然后传入如何比较对象。
回答by recursive
If you have written the function, it's already been derived.
如果您已经编写了该函数,则它已经被派生了。
And given that it's an int function, I'll assume you don't mean the calculus definition of "derive".
鉴于它是一个 int 函数,我假设您不是指“派生”的微积分定义。
回答by ntownsend
If you're thinking of symbolic manipulation of formulae then you're better off doing your derivations in languages like Maple or Mathematica. They're designed for symbolic computation.
如果您正在考虑对公式进行符号操作,那么最好使用 Maple 或 Mathematica 等语言进行推导。它们是为符号计算而设计的。
EDIT: If Maple and Mathematica are too expensive for you then there are other options. Wikipedia has a fairly complete listing of computer algebra packages. http://en.wikipedia.org/wiki/Comparison_of_computer_algebra_systems
编辑:如果 Maple 和 Mathematica 对您来说太贵了,那么还有其他选择。维基百科有一个相当完整的计算机代数包列表。http://en.wikipedia.org/wiki/Comparison_of_computer_algebra_systems
回答by pyon
You can't calculate the exact derivative of a function using a computer program (unless you're doing symbolic math... but that's another, way more complicated, topic).
您无法使用计算机程序计算函数的精确导数(除非您在进行符号数学……但这是另一个更复杂的主题)。
There are several approaches to computing a numericalderivative of a function. The simplest is the centered three-point method:
有几种方法可以计算函数的数值导数。最简单的是中心三点法:
- Take a small number h
- Evaluate
[f(x+h) - f(x-h)] / 2h
- Voilà, an approximation of f'(x), with only two function evaluations
- 取小数h
- 评估
[f(x+h) - f(x-h)] / 2h
- Voilà,f'(x) 的近似值,只有两个函数求值
Another approach is the centered five-point method:
另一种方法是中心五点法:
- Take a small number h
- Evaluate
[f(x-2h) - 8f(x-h) + 8f(x+h) - f(x+2h)] / 12h
- Voilà, a better approximation of f'(x), but it requires more function evaluations
- 取小数h
- 评估
[f(x-2h) - 8f(x-h) + 8f(x+h) - f(x+2h)] / 12h
- 瞧,f'(x) 的更好近似,但它需要更多的函数评估
Another topic is how to implement this using C#. First, you need a delegate that represents a function that maps a subset of the real numbers onto a another subset of the real numbers:
另一个主题是如何使用 C# 实现这一点。首先,您需要一个代表将实数子集映射到另一个实数子集的函数的委托:
delegate double RealFunction(double arg);
Then, you need a routing that evaluates the derivative:
然后,您需要一个评估导数的路由:
public double h = 10e-6; // I'm not sure if this is valid C#, I'm used to C++
static double Derivative(RealFunction f, double arg)
{
double h2 = h*2;
return (f(x-h2) - 8*f(x-h) + 8*f(x+h) - f(x+h2)) / (h2*6);
}
If you want an object-oriented implementation, you should create the following classes:
如果你想要一个面向对象的实现,你应该创建以下类:
interface IFunction
{
// Since operator () can't be overloaded, we'll use this trick.
double this[double arg] { get; }
}
class Function : IFunction
{
RealFunction func;
public Function(RealFunction func)
{ this.func = func; }
public double this[double arg]
{ get { return func(arg); } }
}
class Derivative : IFunction
{
IFunction func;
public static double h = 10e-6;
public Derivative(IFunction func)
{ this.func = func; }
public double this[double arg]
{
get
{
double h2 = h*2;
return (
func[arg - h2] - func[arg + h2] +
( func[arg + h] - func[arg - h] ) * 8
) / (h2 * 6);
}
}
}
回答by Kerry Perret
Another approach can be to leverage the extensions methods using the well-known definition of the derivative number and compute its approximation accordingly.
另一种方法可以是使用众所周知的导数定义来利用扩展方法并相应地计算其近似值。
As it has already been mentioned, this is pretty easy for a numeric approach not a symbolic one:
正如已经提到的,这对于数字方法而不是符号方法来说非常容易:
public partial static class IEnumerableExtensions
{
public static IEnumerable<Double> Derivate1<TSource>(this IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
{
var enumerator = source.GetEnumerator();
enumerator.Reset();
enumerator.MoveNext();
var itemPrevious = enumerator.Current;
var itemNext = default(TSource);
while (enumerator.MoveNext())
{
itemNext = enumerator.Current;
var itemPreviousX = selectorX(itemPrevious);
var itemPreviousY = selectorY(itemPrevious);
var itemNextX = selectorX(itemNext);
var itemNextY = selectorY(itemNext);
var derivative = (itemNextY - itemPreviousY) / (itemNextX - itemPreviousX);
yield return derivative;
itemPrevious = itemNext;
}
}
}
or if you are more into a foreach
fashion
或者如果你更喜欢foreach
时尚
public partial static class IEnumerableExtensions
{
public static IEnumerable<Double> Derivate2<TSource>(IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
{
var itemPrevious = source.First();
source = source.Skip(1);
foreach (var itemNext in source)
{
var itemPreviousX = selectorX(itemPrevious);
var itemPreviousY = selectorY(itemPrevious);
var itemNextX = selectorX(itemNext);
var itemNextY = selectorY(itemNext);
var derivative = (itemNextY - itemPreviousY) / (itemNextX - itemPreviousX);
yield return derivative;
itemPrevious = itemNext;
}
}
}
You can refactor everything as below:
您可以按如下方式重构所有内容:
public static partial class MathHelpers
{
public static Double Derivate(Double xPrevious, Double xNext, Double yPrevious, Double yNext)
{
var derivative = (yNext - yPrevious)/(xNext - xPrevious);
return derivative;
}
}
public static class IEnumerableExtensions
{
public static IEnumerable<Double> Derivate<TSource>(IEnumerable<TSource> source, Func<TSource, Double> selectorX, Func<TSource, Double> selectorY)
{
var itemPrevious = source.First();
source = source.Skip(1);
foreach (var itemNext in source)
{
var derivative = MathHelpers.Derivate(selectorX(itemPrevious), selectorX(itemNext), selectorY(itemPrevious), selectorY(itemNext));
yield return derivative;
itemPrevious = itemNext;
}
}
}