C++ 数值解不';不要分道扬镳。为什么?
我尝试使用Euler方法来近似一个微分方程:C++ 数值解不';不要分道扬镳。为什么?,c++,precision,numerical-integration,C++,Precision,Numerical Integration,我尝试使用Euler方法来近似一个微分方程: u'=3*(u-t) u(0)=1/3 要解决此问题,应使用浮点精度进行大量步骤的发散。这是由于初始数据的舍入误差造成的。 对我的一些朋友来说,这个密码是不同的,但对我来说不是 编译器是否可能正在提高精度 更新评论: @KillzoneKid nog++-Wall-pedantic main.cpp不打印任何内容 @一些程序员认为实际输出是精确解,而由于浮动误差,输出应该发散。类似于7189而不是10+1/3(精确解) @pac0编译后的输出不起作
u'=3*(u-t)
u(0)=1/3
要解决此问题,应使用浮点精度进行大量步骤的发散。这是由于初始数据的舍入误差造成的。
对我的一些朋友来说,这个密码是不同的,但对我来说不是
编译器是否可能正在提高精度
更新评论:
@KillzoneKid nog++-Wall-pedantic main.cpp
不打印任何内容
@一些程序员认为实际输出是精确解,而由于浮动误差,输出应该发散。类似于7189而不是10+1/3(精确解)
@pac0编译后的输出不起作用,因为其他人都在使用非常旧的linux版本(内核2.6),但我将尝试设置编译器选项
现在的趋势是,mac电脑用户(我的朋友)和现代linux用户(me)都会遇到这个问题,而windows或非常旧的linux用户则不会
@1201程序我在XPS15上使用Ubuntu17.10,CLion作为编辑器。
为了简单起见,我使用的是捆绑在操作系统中的g++
#include <iostream>
#include <math.h>
#include <fstream>
using namespace std;
typedef float Real;
Real f(Real t,Real u);
const Real pi=4.0*atan(1.0);
int main() {
Real u,t,T,tau;
// print to file
char n_file[21]={0};
std::cout << "file name: " << std::endl;
std::cin >> n_file ;
ofstream prt(n_file);
prt.precision(15);
//
t=0.0;//start time
T=10.0;//final time
u=1.0/3.0;// u(0)
unsigned long N;
for(int k=1;k<=20;k++){
N=(unsigned long)pow(10,k);
tau=(T-t)/Real(N);
for(unsigned long n=1;n<=N;n++){
u+=tau*f(t,u);
t+=tau;
}
prt << "With " << N << " steps, at time " << tau << "result is " <<u<<endl;
prt << endl << endl << endl;
u = 1.0/3.0;
t = 0.0;
}
//
return 0;
}
//
Real f(Real t, Real u)
{
return 3*(u-t);
}
#包括
#包括
#包括
使用名称空间std;
typedef浮点实数;
实f(实t,实u);
常数实pi=4.0*atan(1.0);
int main(){
真u,t,t,tau;
//打印到文件
字符n_文件[21]={0};
std::cout n_文件;
流prt(n_文件);
精密度(15);
//
t=0.0;//开始时间
T=10.0;//最后一次
u=1.0/3.0;//u(0)
无符号长N;
对于(int k=1;k,u=1.0/3.0+1e-8;
的计算以双精度完成,然后在分配给u时四舍五入到最接近的浮点值。使用Windows和Visual Studio,在从双精度转换为浮点期间,+1e-8会四舍五入,但+1e-7足够大,足以影响浮点结果:
1.0/3.0 + 1e-8 == 1.0/3.0 == 32 bit hex integer 0x3eaaaaab
~= 0.33333334
1.0/3.0 + 1e-7 == 32 bit hex integer 0x3eaaaaae
~= 0.33333343
环境之间的差异可能是浮点控制字的舍入设置问题,也可能是硬件实现问题
我将代码更改为使用2次方的步长计数(在本例中为8次方),并将最大步长限制为对应于浮点尾数部分的有效位数。这消除了发散,部分原因是u的初始值略大于1/3,而t和tau是精确的(因为步长计数是2的幂),部分原因是乘以tau减少的误差大于重复加法增加的误差。将u初始化为1/3-1e-7,和在64步处发散,变成-5770,但对于8步,它是10.30,对于>=512步,它是10.333333
#include <iomanip>
#include <iostream>
#include <math.h>
#include <fstream>
using namespace std;
typedef float Real;
Real f(Real t,Real u);
int main() {
Real u,t,T,tau;
// print to file
char n_file[21]={0};
std::cout << "file name: " << std::endl;
std::cin >> n_file ;
ofstream prt(n_file);
prt.precision(15);
T=10.0; //final time
unsigned long N = 1;
for(int k=1;k<=7;k++){
N *= 8; // # steps is power of 2
u = (Real)(1.0/3.0);
t = 0.0;
tau=T/Real(N);
for(unsigned long n=1;n<=N;n++){
u+=tau*f(t,u);
t+=tau;
}
prt << "With " << setw(8) << N << " steps result is " << u <<endl;
}
return 0;
}
Real f(Real t, Real u)
{
return 3*(u-t);
}
#包括
#包括
#包括
#包括
使用名称空间std;
typedef浮点实数;
实f(实t,实u);
int main(){
真u,t,t,tau;
//打印到文件
字符n_文件[21]={0};
std::cout n_文件;
流prt(n_文件);
精密度(15);
T=10.0;//最后一次
无符号长N=1;
对于(int k=1;kDo),您会收到任何double
tofloat
转换警告?对于某些输入(您需要告诉我们)预期和实际输出是什么?您是否尝试过?“对于我的一些朋友,此代码发散”,如果你在你的机器上编译并给他们可执行文件,是否也有区别?你使用的是哪种编译器/版本?与你的朋友使用的编译器/版本相同吗?不清楚为什么你确定这应该“不同”。抱歉,这是一个测试。原始代码没有。如果您在没有测试的情况下运行代码,最终结果是什么?10.333333…?@Mascarpone-使用Win 7 Pro 64位Visual Studio 2015,它会出现分歧。将步数更改为2的幂可以解决此问题。此外,10^20不适合64位整数,更不用说32位整数,f面包的有效期只有7位数。我更新了我的答案。