主题:Fortran精度问题
			
 tianao87
				 [专家分:0]  发布于 2011-05-16 11:29:00							
			用以下程序计算tent map时间序列,结果大家可以看到迭代十几步之后精度的误差就这么大,完全偏离预期结果,不知道要怎么办,求解!!!!
program tent 
implicit none
   parameter N=1000
   integer :: i
   double precision :: x(N) 
   open(10,file='data.txt')
    x(1)=0.2_8    
    do i=2,N
      x(i)=1.0-2.0*abs(x(i-1)-0.5)
    end do
    do i=1,N
      write(10,*)i,x(i)
    enddo
end
结果:
           1  0.200000000000000     
           2  0.400000000000000     
           3  0.800000000000000     
           4  0.400000000000000     
           5  0.800000000000000     
           6  0.400000000000000     
           7  0.800000000000001     
           8  0.399999999999999     
           9  0.799999999999997     
          10  0.400000000000006     
          11  0.800000000000011     
          12  0.399999999999977     
          13  0.799999999999955     
          14  0.400000000000091     
          15  0.800000000000182
PS:编译环境用的是CVF6.6
			最后更新于:2011-05-16 11:34:00
			
					 
		
			
回复列表 (共16个回复)
		
								
				沙发
				
					
yeg001 [专家分:14390]  发布于 2011-05-16 12:03:00				
				x(i)=1.0_8-2.0_8*abs(x(i-1)-0.5_8)
这样会不会好一些?
不过如果遵守规范的话, 1.0, 2.0, 0.5转换成双精度应该没有问题.
看楼主的结果应该就是截断误差的累加. 每次循环都乘以2.
							 
						
				板凳
				
					
tianao87 [专家分:0]  发布于 2011-05-16 12:08:00				
				[quote]x(i)=1.0_8-2.0_8*abs(x(i-1)-0.5_8)
这样会不会好一些?[/quote]
试过了,结果还是那样!
							 
						
				3 楼
				
					
yeg001 [专家分:14390]  发布于 2011-05-16 12:36:00				
				先问楼主一个问题, 这个程序的目的是不是用来测量截断误差的?
							 
						
				4 楼
				
					
tianao87 [专家分:0]  发布于 2011-05-16 12:50:00				
				[quote]先问楼主一个问题, 这个程序的目的是不是用来测量截断误差的?[/quote]
当然不是,用来生成一个时间序列的,也就是x(N)
							 
						
				5 楼
				
					
yeg001 [专家分:14390]  发布于 2011-05-16 14:08:00				
				分析了一下, 截断误差是由初值x(1)=0.2_8引入的. 后面的算法怎么调整也没用.
把后面输出部分用格式化
write(10,*)i,x(i) => write(10,fmt="(I5,F23.18)")i,x(i)
你会发现二进制浮点数表示无法精确表示0.2, 当2.0*累计到一定程度就出现你所说的精度问题.
这个与语言无关, 不是fortran的问题.
							 
						
				6 楼
				
					
tianao87 [专家分:0]  发布于 2011-05-16 14:43:00				
				[quote]分析了一下, 截断误差是由初值x(1)=0.2_8引入的. 后面的算法怎么调整也没用.
把后面输出部分用格式化
write(10,*)i,x(i) => write(10,fmt="(I5,F23.18)")i,x(i)
你会发现二进制浮点数表示无法精确表示0.2, 当2.0*累计到一定程度就出现你所说的精度问题.
这个与语言无关, 不是fortran的问题.[/quote]
受教了,十分感谢,那么可有办法让我进行迭代之后使截断误差不影响我的结果,迭代十几次就有这么大的误差接受不了!
							 
						
				7 楼
				
					
yeg001 [专家分:14390]  发布于 2011-05-16 15:10:00				
				我不懂这个时间序列怎样才算是对的.
我是想算法可不可以反过来, 从你序列最终终止的1.0开始反过来算出每个时序的数? 而不是随手设定的一个例如0.2这样的常数?
							 
						
				8 楼
				
					
tianao87 [专家分:0]  发布于 2011-05-16 15:16:00				
				[quote]我不懂这个时间序列怎样才算是对的.
我是想算法可不可以反过来, 从你序列最终终止的1.0开始反过来算出每个时序的数? 而不是随手设定的一个例如0.2这样的常数?[/quote]
如果是精确的迭代的话,应该一直是0.8和0.4两个值一个周期序列,结果由于误差的影响使序列最终稳定在0.0了(60个点之后的值全为0.0),这个结果严重影响最终结论啊,搞得我很受伤啊。。。。
							 
						
				9 楼
				
					
dongyuanxun [专家分:7180]  发布于 2011-05-16 15:32:00				
				[quote]我不懂这个时间序列怎样才算是对的.
我是想算法可不可以反过来, 从你序列最终终止的1.0开始反过来算出每个时序的数? 而不是随手设定的一个例如0.2这样的常数?[/quote]
计算机只有计算整型是绝对精确的。
如果你需要精确计算,那么不要使用浮点数,请全部使用整型。
然后再把结果除以一个倍数就是你要的结果。
先明白理论解、数值解、误差限之间的关系。
							 
						
				10 楼
				
					
dongyuanxun [专家分:7180]  发布于 2011-05-16 15:38:00				
				这样误差是最小的
program tent
implicit none
   integer,parameter :: N=1000
   integer :: i
   integer :: x(N)
   open(10,file='data.txt')
    x(1)=2
    do i=2,N
      x(i)=10-2*abs(x(i-1)-5)
    end do
    do i=1,N
      write(10,*)i,x(i)/10._8
    enddo
end
当然也可以输出精确解,以字符串之类的方式构造类型,可以参考各种高精度算法。
							 
									
			
我来回复