我正在尝试使用欧拉方法逼近微分方程:
u'=3*(u-t)
u(0)=1/3
问题应该是浮动精度的大量步骤。这是由于初始数据的舍入误差。 对于我的一些朋友来说,这个代码有所不同,对我而言则不然。
编译器是否可能提高精度?
评论更新:
@KillzoneKid没有g++ -Wall -pedantic main.cpp
不会打印任何内容
@ some-programmer-dude实际输出是确切的解决方案,而输出应该因为浮动错误而发散。像7189而不是10+ 1/3(精确解决方案)
@ pac0编译输出不起作用,因为其他人都使用的是旧版本的linux(内核2.6),但我会尝试设置编译器选项。
趋势是有mac(我的朋友)和现代linux(我)的人遇到这个问题,而Windows或非常老的linux上的人不会。
@ 1201ProgramAlarm我在XPS 15上使用ubuntu 17.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);
}
答案 0 :(得分:1)
u=1.0/3.0 + 1e-8;
的计算以双精度完成,然后在分配给u时舍入到最接近的浮点值。使用Windows和Visual Studio时,+ 1e-8在从double转换为float期间变圆,但+ 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,对于&gt; = 512步,它&# 39; s 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);
}