[英]C# Unity3D Calculus
I want to use Unity to do math kind of like MATLAB, but also science type things in chemistry, physics, and engineering.我想用 Unity 做类似于 MATLAB 的数学运算,也想用化学、物理和工程学做科学类的事情。
Just wanted to ask if these functions sound right for computing derivatives and partial derivatives numerically, and how I might go about doing 2nd partial derivatives and Laplace operator like in formulas like the Schrodinger's Equation, the Heat Equation, and so on?只是想问一下这些函数是否适合以数值方式计算导数和偏导数,以及我如何像薛定谔方程、热方程等公式一样进行二阶偏导数和拉普拉斯算子?
I'm still learning Differential Equations, but wanted to relate it to numerical computation in C# for calculation.我仍在学习微分方程,但想将其与 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;
}
You probably have a little way to go.你可能还有一点路要走。
As a first step, what you should do / must do is作为第一步,您应该/必须做的是
This is the basic pipeline of Unity development (and really all software in our era).这是 Unity 开发的基本管道(实际上是我们这个时代的所有软件)。
If you search the web, you will find the libraries which handle issues such as derivatives, transcendental functions, etc etc如果你在网上搜索,你会发现处理衍生、超越函数等问题的库
you could start with this QA, a number of packages are mentioned!您可以从这个 QA 开始,其中提到了许多软件包!
https://stackoverflow.com/a/34208687/294884 https://stackoverflow.com/a/34208687/294884
By totally familiarizing yourself with existing packages, you will to begin with learn how to package such a thing, API, etc, which is the first thing you have to get comfortable with when you make your own!通过完全熟悉现有的包,您将首先学习如何打包这样的东西、API 等,这是您制作自己的包时必须熟悉的第一件事!
Your implementation is a good approximation (since derivative is a limit and h
is a finite value).您的实现是一个很好的近似值(因为导数是一个极限,而
h
是一个有限值)。 However, I suggest some different code:但是,我建议一些不同的代码:
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);
}
}
If you frequently use Derivative
you can try declaring it as an extension method :如果您经常使用
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) { ... }
Demo: let's find out maximum error when x
within [0 .. 2 * PI)
range for Sin
function演示:让我们找出当
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);
Outcome:结果:
1.64271596325705E-10
Edit: "Central" derivative.编辑: “中央”衍生品。
As we know, derivative is a limit众所周知,导数是一个极限
df/dx == lim (f(x + h) - f(x)) / h
h -> 0
however we can ask: how h
tend to 0
.但是我们可以问:
h
如何趋向于0
。 We have a lot of ways in case of complex numbers ( h
can, say, spiral down to 0
or goes along a strait line);对于复数,我们有很多方法(例如,
h
可以螺旋下降到0
或沿着一条直线); in case of real numbers h
can be either positive ( right semi-derivative) or negative ( left semi-derivative).在实数的情况下,
h
可以是正数(右半导数)或负数(左半导数)。 Usually (standard definition) we require left semi-deivative be equal to right one in order to have derivative:通常(标准定义)我们要求左半导数等于右半导数才能得到导数:
d+f(x) == d-f(x) == df/dx
However, sometime we use lenient definition ("central" derivative):但是,有时我们使用宽松的定义(“中心”导数):
df/dx == (d+f(x) + d-f(x)) / 2
For instance, d(abs(x))/dx
at x = 0
例如,
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.
Please, note that you current code computes in fact right semi-derivative ;请注意,您当前的代码实际上计算的是正确的半导数; in case of
Abs(x)
you'll get wrong 1
.在
Abs(x)
的情况下,你会弄错1
。 0
is a better answer in the context if not in calculus but in, say, engineering (imagine a moving car which does have a velocity).如果不是在微积分中而是在工程中(想象一辆确实有速度的移动汽车),
0
在上下文中是一个更好的答案。 Another issue is that when computing derivative at x
we don't need f
exist at x
.另一个问题是,当计算
x
处的导数时,我们不需要f
存在于x
处。 For instance例如
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
Please, note that derivative df/dx
at x = 0
exists (it's positive infinity).请注意,
x = 0
处的导数df/dx
存在(它是正无穷大)。 That's why when computing derivative we should avoid computing f(x)
.这就是为什么在计算导数时我们应该避免计算
f(x)
。 You current code will return您当前的代码将返回
(h / h + 0 / 0) / h == (1 + NaN) / h == NaN
double.NaN
- derivative doesn't exists (and that is wrong); double.NaN
- 导数不存在(这是错误的); "central" derivative will return “中心”衍生品将回归
(h/h - -h/h) / (2 * h) == 1 / h == some huge number (approximation of +Inf)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.