C++ 等高线积分算法C++;

C++ 等高线积分算法C++;,c++,math,numerical-integration,C++,Math,Numerical Integration,我正试图写一个应用数学程序来计算复杂平面上的轮廓积分。首先,我想为梯形方法编写一个算法,但我有点难以理解它是什么样子。毕竟,我们通常认为梯形方法是二维图,这里我们有f:C->C,所以我们说的是4D 最终,我希望用这个算法计算余数,但当我尝试最简单的简单f(z)=1/z,轮廓是围绕原点的半径为1的圆时,我在1附近没有得到任何结果(这是我应该得到的)。下面是我的梯形法代码: complexCartesian trapezoid(complexCartesian *c1, complexCartesi

我正试图写一个应用数学程序来计算复杂平面上的轮廓积分。首先,我想为梯形方法编写一个算法,但我有点难以理解它是什么样子。毕竟,我们通常认为梯形方法是二维图,这里我们有f:C->C,所以我们说的是4D

最终,我希望用这个算法计算余数,但当我尝试最简单的简单f(z)=1/z,轮廓是围绕原点的半径为1的圆时,我在1附近没有得到任何结果(这是我应该得到的)。下面是我的梯形法代码:

complexCartesian trapezoid(complexCartesian *c1, complexCartesian *c2)
{
     complexCartesian difference = *c1 - *c2;
     complexCartesian ans(0.5 * (function(c1).real + function(c2).real) * 
                                                     difference.mag(), 
                          0.5 * (function(c1).imag + function(c2).imag) *
                                                     difference.mag());
     return ans;
}
这里,“函数”只计算f(z)=1/z(我确信这是正确的),complexCartesian是我针对a+bi格式的复杂点的类:

class complexCartesian
{
    public:
    double real;
    double imag;

    complexCartesian operator+ (const complexCartesian& c) const;
    complexCartesian operator- (const complexCartesian& c) const;
    complexCartesian(double realLocal, double imagLocal);
    double mag(); //magnitude
    string toString();
    complexPolar toPolar();
};
我很有信心,这些函数都在做它应该做的事情。(我知道有一个标准的复数类,但我想我会写自己的练习)。为了实际集成,我使用以下方法:

double increment = .00001;
double radius = 1.0;
complexCartesian res(0,0); //result
complexCartesian previous(1, 0); //start the point 1 + 0i

for (double i = increment; i <= 2*PI; i+=increment)
{
    counter++;
    complex cur(radius * cos(i), radius * sin(i));
    res = res + trapezoid(&cur, &previous);
    previous = cur;
}

cout << "computed at " << counter << " values " << endl;
cout << "the integral evaluates to " << res.toString() << endl;
双增量=.00001;
双半径=1.0;
复自流res(0,0)//结果
复自流上一代(1,0)//从点1+0i开始

对于(double i=increment;i检查梯形规则:实际上,轮廓积分定义为黎曼和的极限,$\sum\u k f(z\u k)\delta z_k$,其中乘法被理解为复数乘法,这不是你要做的。

你的梯形规则并不是真的计算复数梯形规则,而是一些介于实数和复数之间的弗兰肯斯坦

下面是一个利用
std::complex
并“正确”工作的自包含示例

#包括
#包括
#包括
#包括
使用std::cout;
使用std::endl;
typedef-std::复杂cplx;
typedef cplx(*函数)(常量cplx&);
typedef cplx(*路径)(双精度);
typedef cplx(*规则)(函数,常数cplx&,常数cplx&);
cplx inv(常数cplx&z)
{
返回cplx(1,0)/z;
}
cplx单位_圆(双t)
{
常数双r=1.0;
常数双c=2*M_π;
返回cplx(r*cos(c*t),r*sin(c*t));
}
cplx imag\U exp\U line\U pi(双t)
{
返回exp(cplx(0,M_PI*t));
}
cplx梯形(函数f、常数cplx&a、常数cplx&b)
{
返回0.5*(b-a)*(f(a)+f(b));
}
cplx集成(函数f、路径、规则)
{
int计数器=0;
双增量=.0001;
cplx积分(0,0);
cplx上一点=路径(0.0);

对于(double i=increment;i我喜欢这里发布的两个解决方案,但我提出的另一个解决方案是参数化复坐标并使用极坐标。因为(在本例中)我只在围绕极点的小圆圈上进行计算,所以坐标的极坐标形式只有一个变量(θ)。这将4D梯形规则变成了花园式的2D规则。当然,如果我想沿着非圆形轮廓积分,这是行不通的,我需要上面的解决方案。

我已经有一段时间没有做轮廓积分了,但是上面的积分是否有可能计算为0?1/z在原点有一个极点,而resi由于这个极点是1(lim_{z\to 0}z(1/z)=1)。因此积分应该通过留数定理计算为2(pi)(i)。啊,好的。谢谢你让我知道!我很好奇这是否只是数值不稳定性。有什么特别的原因你不想使用极坐标吗?我认为δz是一个量级。因此差。mag().你的意思是我应该乘以复数差,而不是实数差。mag()?是的。例如,请参见本文中的示例6.6:是的--使用复数表示“stuff”的规则就是你简单地用复数计算一切。你不能随意转移到用从复数中任意导出的实数计算公式的一部分。这就是使用
mag()
所做的:你在复数中有一个非常好的公式,然后你选择毫无理由地破坏它:)
#include <cmath>
#include <cassert>
#include <complex>
#include <iostream>

using std::cout;
using std::endl;
typedef std::complex<double> cplx;

typedef cplx (*function)(const cplx &);
typedef cplx (*path)(double);
typedef cplx (*rule)(function, const cplx &, const cplx &);

cplx inv(const cplx &z)
{
    return cplx(1,0)/z;
}

cplx unit_circle(double t)
{
    const double r = 1.0;
    const double c = 2*M_PI;
    return cplx(r*cos(c*t), r*sin(c*t));
}

cplx imag_exp_line_pi(double t)
{
    return exp(cplx(0, M_PI*t));
}

cplx trapezoid(function f, const cplx &a, const cplx &b)
{
    return 0.5 * (b-a) * (f(a)+f(b));
}

cplx integrate(function f, path path_, rule rule_)
{
    int counter = 0;
    double increment = .0001;
    cplx integral(0,0);
    cplx prev_point = path_(0.0);
    for (double i = increment; i <= 1.0; i += increment) {
        const cplx point = path_(i);
        integral += rule_(f, prev_point, point);
        prev_point = point;
        counter ++;
    }

    cout << "computed at " << counter << " values " << endl;
    cout << "the integral evaluates to " << integral << endl;
    return integral;
}

int main(int, char **)
{
    const double eps = 1E-7;
    cplx a, b;
    // Test in Octave using inverse and an exponential of a line
    // z = exp(1i*pi*(0:100)/100);
    // trapz(z, 1./z)
    // ans =
    //   0.0000 + 3.1411i
    a = integrate(inv, imag_exp_line_pi, trapezoid);
    b = cplx(0,M_PI);
    assert(abs(a-b) < eps*abs(b));

    // expected to be 2*PI*i
    a = integrate(inv, unit_circle, trapezoid);
    b = cplx(0,2*M_PI);
    assert(abs(a-b) < eps*abs(b));

    return 0;
}