C++ C/C+中的衍生品+;?

C++ C/C+中的衍生品+;?,c++,c,math,numerical,symbolic-math,C++,C,Math,Numerical,Symbolic Math,我有一些表达式,比如x^2+y^2,我想用于一些数学计算。我想做的一件事是对表达式进行偏导数 因此,如果f(x,y)=x^2+y^2,那么f关于x的部分将是2x,关于y的部分将是2y 我用有限差分法写了一个很小的函数,但是我在浮点精度方面遇到了很多问题。例如,我的结果是1.99234,而不是2。是否有支持符号差异化的库?还有其他建议吗?要使数值微分“正确”(在最小化误差的意义上)可能相当棘手。要开始,您可能需要查看上的“数值公式”部分 对于免费的符号数学软件包,您应该看看。您还可以查看一个自包含

我有一些表达式,比如
x^2+y^2
,我想用于一些数学计算。我想做的一件事是对表达式进行偏导数

因此,如果
f(x,y)=x^2+y^2
,那么
f
关于
x
的部分将是
2x
,关于
y
的部分将是
2y


我用有限差分法写了一个很小的函数,但是我在浮点精度方面遇到了很多问题。例如,我的结果是
1.99234
,而不是
2
。是否有支持符号差异化的库?还有其他建议吗?

要使数值微分“正确”(在最小化误差的意义上)可能相当棘手。要开始,您可能需要查看上的“数值公式”部分

对于免费的符号数学软件包,您应该看看。您还可以查看一个自包含的纯python符号数学包。您会发现Symphy更容易探索,因为您可以从Python命令行交互地使用它


在商业方面,Mathematica和Maple都有C API。您需要安装/许可版本的程序才能使用这些库,但两者都可以轻松实现您所追求的符号差异。

这是一种旁白,因为它适用于Lisp而不是C/C++,但是它可以帮助其他人寻找类似的任务,或者您可以自己在C/C++中实现类似的东西。SICP有一些关于lisp主题的讲座:

  • 衍生规则
  • 代数规则

  • 在Lisp中,它非常简单(在其他具有强大模式匹配和多态类型的函数式语言中也是如此)。在C中,您可能需要大量使用枚举和结构来获得相同的能力(更不用说分配/解除分配)。你可以在不到一小时的时间内用ocaml编写出你所需要的代码——我认为打字速度是限制因素。如果您需要C,您实际上可以从C调用ocaml(反之亦然)。

    我已经用几种不同的语言实现了这样的库,但不幸的是不是C。如果您只处理多项式(和、积、变量、常数和幂),这是非常容易的。触发功能也不算太差。任何更复杂的事情,你可能会更好地花时间去掌握别人的图书馆

    如果你决定自己动手,我有一些建议可以简化你的生活:

    • 使用不可变数据结构(纯函数数据结构)表示表达式

    • 用于为您管理内存

    • 要表示线性和,请使用有限映射(例如,二元搜索树)将每个变量映射到其系数


    如果你愿意嵌入到你的C代码中并在那里进行计算,我已经把我的Lua代码放在了。更好的特性之一是,它可以接受符号表达式,对其进行区分,并将结果编译为Lua。当然,您将找不到任何文档:-(

    如果这确实是您想要使用的函数类型,那么编写一个类库就足够简单了。从单个项开始,使用系数和指数。使用一个多项式,它将由一组项组成


    如果您为感兴趣的数学方法定义了一个接口(例如,add/sub/mul/div/differention/integrate),您正在查看一个GoF复合模式。术语和多项式都将实现该接口。多项式只需在其集合中的每个术语上进行迭代。

    利用现有的包当然比编写自己的包容易,但如果您决定编写自己的包,并且准备花一些时间了解C++中一些暗的角落,你可以使用这个方法来设计你自己的库。

    基本上,Boost .Pro允许您将任何有效的C++表达式转换为“代码> x*x+y*y//>”,基本上是嵌套的<代码>结构> <代码> s的表达式的解析树的表示,然后通过调用<代码> PROTO::在树上。默认情况下,

    proto::eval()
    用于计算树,就像它已经直接运行过一样,尽管没有理由不能修改每个函数或运算符的行为以采用符号导数


    虽然这是一个非常复杂的解决方案,但它比用C++模板元编程技术来滚动自己的表达式模板要容易得多。

    如果你正在进行数值微分(“在x=x0处评估f(x)的导数),你知道你是方程组。(我不建议用户输入),这是一个用C++模板库来求解数值导数。它非常快速,准确。

    只计算一阶导数是很微不足道的。 但让它变快是一门艺术。 您需要一个类,其中包含

    • 价值
    • 导数值与自变量的数组
    然后,您将编写加法和减法等运算符,以及类似sin()的函数,它们实现了此操作的基本规则和众所周知的规则

    为了计算高阶导数,应该使用截断泰勒级数。 您还可以将上述类应用于自身——值和派生值的类型应该是模板参数。 但这意味着衍生品的计算和存储不止一次

    截断泰勒级数--有两个库可用于此函数:


    您可以通过两种简单的方法提高数值微分的精度

  • 使用较小的增量。您似乎
    #include <iostream>
    #include "fadiff.h"
    
    using namespace fadbad;
    
    F<double> func(const F<double>& x, const F<double>& y)
    {
        return x*x + y*y;
    }
    
    int main()
    {
        F<double> x,y,f;     // Declare variables x,y,f
        x=1;                 // Initialize variable x
        x.diff(0,2);         // Differentiate with respect to x (index 0 of 2)
        y=1;                 // Initialize variable y
        y.diff(1,2);         // Differentiate with respect to y (index 1 of 2)
        f=func(x,y);         // Evaluate function and derivatives
    
        double fval=f.x();   // Value of function
        double dfdx=f.d(0);  // Value of df/dx (index 0 of 2)
        double dfdy=f.d(1);  // Value of df/dy (index 1 of 2)
    
        std::cout << "    f(x,y) = " << fval << std::endl;
        std::cout << "df/dx(x,y) = " << dfdx << std::endl;
        std::cout << "df/dy(x,y) = " << dfdy << std::endl;
    
        return 0;
    }
    
        f(x,y) = 2
    df/dx(x,y) = 2
    df/dy(x,y) = 2
    
    #include <iostream>
    #include "fadiff.h"
    
    using namespace fadbad;
    
    F<double> func(const F<double>& x)
    {
        return sin(x);
    }
    
    
    
    int main()
    {
        F<double> f,x;
        double dfdx;
        x = 0.0;
        x.diff(0,1);
        f = func(x);
        dfdx=f.d(0);
    
    
        for (int i(0); i < 8; ++i ){
            std::cout << "       x: " << x.val()        << "\n"
                      << "    f(x): " << f.x()          << "\n" 
                      << " fadDfdx: " << dfdx           << "\n"
                      << "trueDfdx: " << cos(x.val())   << std::endl;
            std::cout << "=========================="   << std::endl;
    
            x += 0.1;
            f = func(x);
            dfdx=f.d(0);
        }
    
    
        return 0;
    }
    
           x: 0
        f(x): 0
     fadDfdx: 1
    trueDfdx: 1
    ==========================
           x: 0.1
        f(x): 0.0998334
     fadDfdx: 0.995004
    trueDfdx: 0.995004
    ==========================
           x: 0.2
        f(x): 0.198669
     fadDfdx: 0.980067
    trueDfdx: 0.980067
    ==========================
           x: 0.3
        f(x): 0.29552
     fadDfdx: 0.955336
    trueDfdx: 0.955336
    ==========================
           x: 0.4
        f(x): 0.389418
     fadDfdx: 0.921061
    trueDfdx: 0.921061
    ==========================
           x: 0.5
        f(x): 0.479426
     fadDfdx: 0.877583
    trueDfdx: 0.877583
    ==========================
           x: 0.6
        f(x): 0.564642
     fadDfdx: 0.825336
    trueDfdx: 0.825336
    ==========================
           x: 0.7
        f(x): 0.644218
     fadDfdx: 0.764842
    trueDfdx: 0.764842
    ==========================