求解迭代二次方程会产生噪声

时间:2018-02-11 11:55:45

标签: c++

我正在尝试解决形式的二次方程式:

$ x ^ 2 + 8.888e-5 x - (2.777e-6 * t + 9.34694e-10)= 0 $。

其中't'是基于迭代的变量。这类似于指数衰减函数。我试图在C ++中实现相同的功能(附带代码)。然而,我可以看到行为/趋势,当衰变相对于't'变小时,我看到解决方案中有一些噪音“摆动”。

我教过我可以归咎于编译器的精确度(5.4.0),但是我的朋友认为使用长双数据类型(e-10)值应该是准确的。

附件是我下面的Test.C(例如使用t_end为0.03,numTimeSteps为4500)和我看到的摆动。 Noise with the solution请使用“编辑”文件与gnuplot进行绘图。任何人都可以暗示我如何克服这种噪音吗?

TEST.C

#include <iostream>
#include <cmath>
#include <fstream>
#include <stdlib.h>

#define PI 3.141592

using namespace std;

int main ()
{
    long double t_start = 0.;               /*init time*/
    long double t_end;                      /*end time: user  specified*/
    int numTimeSteps;                       /*user specified*/
    long double dt;                         /*(t_end-t_start)/numTimeSteps*/
    cout << "Enter the end time, number of time steps between t_start and t_end" << endl;
    cin >> t_end >> numTimeSteps;
    dt = (t_end - t_start)/numTimeSteps;
    long double time[numTimeSteps]; 
    long double LHS[numTimeSteps];

    /*Terms of quadratic equation: ax^2 + bx + c =0
     * a and b are constants for test case */
    long double a = 1;
    long double b = 8.888e-5;

    long double determinant[numTimeSteps]; 

    long double root1[numTimeSteps], root2[numTimeSteps];
    long double xm[numTimeSteps];

    for (int i = 0; i <= numTimeSteps; i++)
    {
        time[i] = (t_start)+ (i*dt);
        /*Find LHS of equation based on time and other constants*/
        LHS[i] = -(2.777e-6*time[i]+9.34694e-10);

        cout << "Step = " << i << "\t" << time[i] << "\t" << LHS[i] << endl;

        /*Finding roots of Q.Eqn.
         *Find determinant and check for real roots less than 400e-6*/
        determinant[i] = pow(b,2) - 4.*a*LHS[i];
        cout << "Determinant [" << i << "] = " << determinant[i] << endl;

        /*Case1: Roots are real and equal*/
        if (determinant[i] == 0)    
        {
            root1[i] = root2[i] = -b/(2.*a);
            cout << "Determinant is 0: roots are real and equal" << endl;
            cout << root1[i] << endl;
            cout << "\t \t *** \t \t " << endl;
        } 
        /*Case2: Roots are real and different*/
        else if (determinant[i] > 0)
        {
            root1[i] = (-b+sqrt(determinant[i]))/(2.*a);
            root2[i] = (-b-sqrt(determinant[i]))/(2.*a);
            cout << "Determinant is > 0: roots are real and different" << endl;
            cout << "Root1 = " << root1[i] << " Root2 = " << root2[i] << endl;
            cout << "\t \t *** \t \t " << endl;
        }
        else  
            cout << "Determinant is < 0: roots are imaginary" << endl;
    } 

    for (int i = 1; i <= numTimeSteps; i++)
    {
        if (root1[i] > root1[i-1] && root1[i] < 400e-6)
            xm[i] = root1[i];
        else
            xm[i] = 0.;
        cout << "xm = " << xm[i] << endl; 
    }

    ofstream myfile;
    myfile.open("xm");

    if (myfile.is_open())
    {
        for (int i = 1; i <= numTimeSteps; i++)
            myfile << time[i] << "\t" << xm[i] << endl;
        myfile.close();
    }

    return 0;
}

gnuplot要运行的编辑文件:

#!/bin/bash

paste xm| awk '{print $1}' > TimeAllTest
paste xm| awk '{print $2}' > xmTest
awk 'NR>1{print $1-p}{p=$1}' TimeAllTest > dt
awk '{if (NR!=1) {print}}' TimeAllTest > Time
awk 'NR>1{print $1-p}{p=$1}' xmTest > dxmTest
paste Time dt dxmTest | awk '{print $1, ($3/$2)}' > tvsuTest

感谢。

1 个答案:

答案 0 :(得分:2)

这似乎是输出精度的问题。程序生成的xm文件包含

等行
0.0299933 0.00469697

因此大多数长双尾数已经丢失了。此外,awk脚本还使用awk的默认精度打印,在以后的行中再次引发同样的问题。

myfile.open("xm");
myfile.precision(20); // 20 digits of precision in output

进入C ++程序并像这样更改awk脚本:

#!/bin/bash

paste xm| awk '{print $1}' > TimeAllTest
paste xm| awk '{print $2}' > xmTest

# Note: printf instead of print
awk 'NR>1{ printf("%.20f\n", $1-p) }{p=$1}' TimeAllTest > dt
awk '{if (NR!=1) {print}}' TimeAllTest > Time
awk 'NR>1{printf("%.20f\n", $1-p) }{p=$1}' xmTest > dxmTest
paste Time dt dxmTest | awk '{ printf("%.20f %.20f\n", $1, ($3/$2)) }' > tvsuTest

修复了问题:

enter image description here

您可能还想考虑使用sqrtl代替sqrt(或明确std::sqrt)。我认为现在的方式,取决于gcc 5.4的libstdc ++头结构,可以使用旧的sqrt C函数,并使用double值而不是long double值。 pow / powl / std::pow也是如此,尽管我真的只使用b * b