[英]C# Unity3D Calculus
我想用 Unity 做类似于 MATLAB 的数学运算,也想用化学、物理和工程学做科学类的事情。
只是想问一下这些函数是否适合以数值方式计算导数和偏导数,以及我如何像薛定谔方程、热方程等公式一样进行二阶偏导数和拉普拉斯算子?
我仍在学习微分方程,但想将其与 C# 中的数值计算联系起来进行计算。
public double Derivative(Func<double, double> function, double x, double h)
{
return (function(x + h) - function(x)) / h;
}
public double SecondDerivative(Func<double, double> function, double x, double h)
{
return (function(x + h) - 2 * function(x) + function(x - h)) / (h * h);
}
public double ThirdDerivative(Func<double, double> function, double x, double h)
{
return (function(x + 3 * h) - 3 * function(x + 2 * h) + 3 * function(x + h) - function(x)) / (h * h * h);
}
public double PartialDerivativeX(Func<double, double, double> function, double x, double y, double h)
{
return (function(x + h, y) - function(x, y)) / h;
}
public double PartialDerivativeY(Func<double, double, double> function, double x, double y, double h)
{
return (function(x, y + h) - function(x, y)) / h;
}
你可能还有一点路要走。
作为第一步,您应该/必须做的是
这是 Unity 开发的基本管道(实际上是我们这个时代的所有软件)。
如果你在网上搜索,你会发现处理衍生、超越函数等问题的库
您可以从这个 QA 开始,其中提到了许多软件包!
https://stackoverflow.com/a/34208687/294884
通过完全熟悉现有的包,您将首先学习如何打包这样的东西、API 等,这是您制作自己的包时必须熟悉的第一件事!
您的实现是一个很好的近似值(因为导数是一个极限,而h
是一个有限值)。 但是,我建议一些不同的代码:
public static class MyMath {
// static: we don't want "this"
// Func<double, double> return value: derivative is a function, not a value.
// If we want a point - double - let's name the method as DerivativeAt
// No h - we can't provide correct h for all possible x
public static Func<double, double> Derivative(Func<double, double> function) {
//DONE: Validate public methods arguments
if (null == function)
throw new ArgumentNullException("function");
return new Func<double, double>((x) => {
// Let's compute h for given x
// Easiest, but not the best
double h = Math.Abs(x) < 1e-10 ? 1e-16 : x / 1.0e6;
// "Central" derivative is often a better choice then right one ((f(x + h) - f(x))/h)
return (function(x + h) - function(x - h)) / (2.0 * h);
});
}
// h = 0.0: be nice and let user has no idea what step is reasonable
public static double DerivativeAt(Func<double, double> function,
double x,
double h = 0.0) {
//DONE: Validate public methods arguments
if (null == function)
throw new ArgumentNullException("function");
// If user don't want to provide h, let's compute it
if (0 == h)
h = Math.Abs(x) < 1e-10 ? 1e-16 : x / 1.0e6; // Easiest, but not the best
// "Central" derivative is often a better choice then right one ((f(x + h) - f(x))/h)
return (function(x + h) - function(x - h)) / (2.0 * h);
}
}
如果您经常使用Derivative
,您可以尝试将其声明为扩展方法:
public static Func<double, double> Derivative(this Func<double, double> function) {...}
public static double DerivativeAt(this Func<double, double> function,
double x,
double h = 0.0) { ... }
演示:让我们找出当x
在[0 .. 2 * PI)
范围内的Sin
函数时的最大误差
// We don't want to repeat pesky "MyMath" in "MyMath.Derivative"
using static MyNamespace.MyMath;
...
// Derivative of Sin (expected to be Cos)
var d_sin = Derivative(x => Math.Sin(x));
double maxError = Enumerable
.Range(0, 1000)
.Select(i => 2.0 * Math.PI * i / 1000.0)
.Select(x => Math.Abs(d_sin(x) - Math.Cos(x))) // d(sin(x)) / dx == cos(x)
.Max();
Console.WriteLine(maxError);
结果:
1.64271596325705E-10
编辑: “中央”衍生品。
众所周知,导数是一个极限
df/dx == lim (f(x + h) - f(x)) / h
h -> 0
但是我们可以问: h
如何趋向于0
。 对于复数,我们有很多方法(例如, h
可以螺旋下降到0
或沿着一条直线); 在实数的情况下, h
可以是正数(右半导数)或负数(左半导数)。 通常(标准定义)我们要求左半导数等于右半导数才能得到导数:
d+f(x) == d-f(x) == df/dx
但是,有时我们使用宽松的定义(“中心”导数):
df/dx == (d+f(x) + d-f(x)) / 2
例如, d(abs(x))/dx
在x = 0
d-abs(x) = -1
d+abs(x) = 1
d abs(x) / dx doesn't exist (standard definition)
d abs(x) / dx = 0 "central", lenient definition.
请注意,您当前的代码实际上计算的是正确的半导数; 在Abs(x)
的情况下,你会弄错1
。 如果不是在微积分中而是在工程中(想象一辆确实有速度的移动汽车), 0
在上下文中是一个更好的答案。 另一个问题是,当计算x
处的导数时,我们不需要f
存在于x
处。 例如
f(x) = x / abs(x) which can be put as
-1 when x < 0
f(x) = doesn't exist when x = 0
+1 when x > 0
请注意, x = 0
处的导数df/dx
存在(它是正无穷大)。 这就是为什么在计算导数时我们应该避免计算f(x)
。 您当前的代码将返回
(h / h + 0 / 0) / h == (1 + NaN) / h == NaN
double.NaN
- 导数不存在(这是错误的); “中心”衍生品将回归
(h/h - -h/h) / (2 * h) == 1 / h == some huge number (approximation of +Inf)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.