【问题标题】:Calculating a derivative with Math.NET C#使用 Math.NET C# 计算导数
【发布时间】:2016-03-16 08:48:44
【问题描述】:

我正在寻找一个简单的函数,它可以接受一个双精度值数组并返回数学导数。

Math.NET 似乎有这样的功能,但它要求以下语法:

double FirstDerivative(Func<double, double> f, double x)

我不确定我为什么需要指定一个函数。我只想要一个可以向其传递数据的预先存在的函数。

【问题讨论】:

  • 你看到这个帖子了吗,Mathematical Derivation with C#
  • @ChrisHaas - 你让我免于输入 this answer 但写得不太好。
  • 嗯……曲线下方的面积实际上是积分,而不是导数……
  • 数组的导数没有多大意义。你的数据数组来自哪里?我知道在哪里使用离散点集计算导数的唯一上下文是当您想要对函数的导数进行数值近似时(这可能是 FirstDerivative 函数所做的,但它离散化了函数本身) .
  • 你想要一个原始数组中连续点对之间差异的数组吗?

标签: c#


【解决方案1】:

如果你不反对 Math.Net 以外的库,你可以试试 AlgLib 和他们的 spline1ddiff 函数

构建样条线很容易,Akima 样条线通过点看起来很流畅。如果您想要一个接收一组数据并返回导数的方法,这里有一个使用 AlgLib 数学库的示例:

public static void CalculateDerivatives(this Dictionary<double, double> inputPoints, out Dictionary<double, double> firstDerivatives, out Dictionary<double, double> secondDerivatives)
{
        var inputPointsXArray = inputPoints.Keys.ToArray();
        var inputPointsYArray = inputPoints.Values.ToArray();

        spline1dinterpolant akimaSplineToDifferentiate;
        alglib.spline1dbuildakima(inputPointsXArray, inputPointsYArray, out akimaSplineToDifferentiate);

        firstDerivatives = new Dictionary<double, double>();
        secondDerivatives = new Dictionary<double, double>();
        foreach (var pair in inputPoints)
        {
            var xPoint = pair.Key;
            double functionVal, firstDeriv, secondDeriv;
            alglib.spline1ddiff(akimaSplineToDifferentiate, xPoint, out functionVal, out firstDeriv, out secondDeriv);

            firstDerivatives.Add(point, firstDeriv);
            secondDerivatives.Add(point, secondDeriv);
        }
}

警告:Akima Spline 在您的数据集范围之外具有不可预测的行为。

【讨论】:

    【解决方案2】:

    获取您的数据点并创建一个 Math.NET Numerics Cubic Spline 对象。然后使用.Differentiate()方法得到你想要的每个点的斜率。

    示例

    试试下面的代码:

    static class Program
    {
        const int column_width = 12;
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main(string[] args)
        {
            var xvec = new DenseVector(new double[] { 0.0, 1.0, 2.0, 3.0, 4.0 });
            var yvec = new DenseVector(new double[] { 3.0, 2.7, 2.3, 1.6, 0.2 });
            Debug.WriteLine("Input Data Table");
            Debug.WriteLine($"{"x",column_width} {"y",column_width}");
            for(int i = 0; i < xvec.Count; i++)
            {
                Debug.WriteLine($"{xvec[i],column_width:G5} {yvec[i],column_width:G5}");
            }
            Debug.WriteLine(" ");
            var cs = CubicSpline.InterpolateNatural(xvec, yvec);
    
            var x = new DenseVector(15);
            var y = new DenseVector(x.Count);
            var dydx = new DenseVector(x.Count);
            Debug.WriteLine("Interpoaltion Results Table");
            Debug.WriteLine($"{"x",column_width} {"y",column_width} {"dy/dx",column_width}");
            for(int i = 0; i < x.Count; i++)
            {
                x[i] = (4.0*i)/(x.Count-1);
                y[i] = cs.Interpolate(x[i]);
                dydx[i] = cs.Differentiate(x[i]);
                Debug.WriteLine($"{x[i],column_width:G5} {y[i],column_width:G5} {dydx[i],column_width:G5}");
            }
    
    
        }
    }
    

    并查看调试输出:

    Input Data Table
               x            y
               0            3
               1          2.7
               2          2.3
               3          1.6
               4          0.2
    
    Interpoaltion Results Table
               x            y        dy/dx
               0            3     -0.28214
         0.28571        2.919     -0.28652
         0.57143       2.8354     -0.29964
         0.85714       2.7469      -0.3215
          1.1429       2.6509     -0.35168
          1.4286       2.5454     -0.38754
          1.7143        2.429     -0.42864
               2          2.3       -0.475
          2.2857        2.154     -0.55809
          2.5714       1.9746      -0.7094
          2.8571       1.7422     -0.92894
          3.1429       1.4382      -1.1979
          3.4286       1.0646      -1.4034
          3.7143      0.64404      -1.5267
               4          0.2      -1.5679
    

    【讨论】:

    • 您能否通过一些代码示例展示它是如何实现的?
    • 请注意,自然样条曲线末端的二阶导数设置为零(这就是绿线末端不变的原因)。还有其他选项指定结束斜率并且二阶导数不为零。
    【解决方案3】:

    感谢您的回复。

    我相信我需要遍历数组,调用 Math.NET 中的微分函数,或者干脆自己编写(上升超过运行)计算。

    【讨论】:

    • 不要只取连续点的简单差异,因为结果会很不稳定。您必须对点进行插值并区分插值。请在帖子中分享一些数据点,以便我们尝试不同的事情。
    【解决方案4】:

    这里有函数的衍生扩展

    public static Func<double[], double> Derivative(this Func<double[], double> func, int derivativeIndex)
    {
        double step = 0.001;
        return income => 
        {
            double[] increasedIncome = (double[])income.Clone();
            increasedIncome[derivativeIndex] += step;
    
            double[] decreasedIncome = (double[])income.Clone();
            decreasedIncome[derivativeIndex] -= step;
    
            return (func(increasedIncome) - func(decreasedIncome)) / (2 * step);
        };
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-07-01
      • 1970-01-01
      • 2012-07-30
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多