【问题标题】:Mathematical function differentiation with C#?用 C# 进行数学函数微分?
【发布时间】:2015-12-11 00:18:12
【问题描述】:

我看到我可以用 (say) 声明一个函数

public double Function(double parameter)

但是如果我确实想取那个函数的导数呢?

【问题讨论】:

  • 我认为您的意思是“差异化”。你想用数字完成吗?您真的是要使用整数作为返回类型和参数而不是浮点数吗?
  • float 或 double,这只是我想做的一个例子。
  • 你需要重写你的问题。我已经阅读了好几遍,但仍然没有完全理解您的要求。从答案中,我可以看出我不是唯一一个有这个问题的人。

标签: c# math function


【解决方案1】:

您无法使用计算机程序计算函数的精确导数(除非您正在做符号数学......但这是另一个更复杂的主题)。

有几种方法可以计算函数的数值导数。最简单的就是居中三点法:

  • 取一个小数h
  • 评估 [f(x+h) - f(x-h)] / 2h
  • 瞧,f'(x) 的近似值,只有两个函数评估

另一种方法是居中五点法:

  • 取一个小数h
  • 评估[f(x-2h) - 8f(x-h) + 8f(x+h) - f(x+2h)] / 12h
  • 瞧,f'(x) 的更好近似,但它需要更多的函数评估

另一个主题是如何使用 C# 实现这一点。首先,您需要一个代表函数的委托,该函数将实数的子集映射到实数的另一个子集:

delegate double RealFunction(double arg);

然后,您需要一个评估导数的路由:

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);
}

如果你想要一个面向对象的实现,你应该创建以下类:

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);
        }
    }
}

【讨论】:

  • 对 C# 中的数值微分非常简洁和简单的解释。谢谢:)
  • @Andrew Burnett-Thompson:谢谢。
  • @LaRiFaRi:抱歉,这些天我的 C# 生锈了,我更像是一个 Haskell 和 ML 程序员。但总体思路如下: 1. 创建一个常规方法,接受 double 并返回 double,2. 构造一个 Function,将您之前创建的方法作为其委托参数传递, 3. 构造一个 @ 987654329@,传递您之前创建的Function 作为其参数。
  • @sdjuan:要调用IFunction,请使用运算符[],就像索引数组一样。
  • 道歉:Double,arg 变量是 x 两种不同的方法。
【解决方案2】:

如果您正在考虑对公式进行符号操作,那么最好使用 Maple 或 Mathematica 等语言进行推导。它们专为符号计算而设计。

编辑:如果 Maple 和 Mathematica 对您来说太贵了,那么还有其他选择。维基百科有一个相当完整的计算机代数包列表。 http://en.wikipedia.org/wiki/Comparison_of_computer_algebra_systems

【讨论】:

  • 是的,这就是我想要的。创建一个函数并对其进行操作。我需要第三方吗?
【解决方案3】:

您在考虑 Lambda 表达式吗?

基本上你可以将一个函数传递给一个函数。

所以想想对一个对象进行排序。 根据对象的性质将有助于确定对象的排序方式。

但您仍然可以创建一个通用排序函数,然后传入如何比较对象。

【讨论】:

    【解决方案4】:

    另一种方法是利用众所周知的导数定义来利用扩展方法并相应地计算其近似值。

    正如已经提到的,这对于数字方法而不是符号方法来说非常容易:

    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;
            }
        }
    }
    

    或者如果你更喜欢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;
            }
        }
    }
    

    您可以按如下方式重构所有内容:

    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;
            }
        }
    }
    

    【讨论】:

      【解决方案5】:

      如果你写了函数,它已经被派生了。

      鉴于它是一个 int 函数,我假设您不是指“导数”的微积分定义。

      【讨论】:

      • 微积分中导数运算的口头形式是“微分”,而不是“推导”。
      • 啊。妥当注明。学习。我喜欢它。
      猜你喜欢
      • 1970-01-01
      • 2023-04-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多