我正在尝试解决形式的二次方程式:
$ 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)和我看到的摆动。 请使用“编辑”文件与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
感谢。
答案 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
修复了问题:
您可能还想考虑使用sqrtl
代替sqrt
(或明确std::sqrt
)。我认为现在的方式,取决于gcc 5.4的libstdc ++头结构,可以使用旧的sqrt
C函数,并使用double
值而不是long double
值。 pow
/ powl
/ std::pow
也是如此,尽管我真的只使用b * b
。