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++模板库来求解数值导数。它非常快速,准确。 只计算一阶导数是很微不足道的。 但让它变快是一门艺术。 您需要一个类,其中包含- 价值
- 导数值与自变量的数组
您可以通过两种简单的方法提高数值微分的精度
#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
==========================