Fortran舍入错误
我有一个简单的代码,它用圆柱体包围的区域标记节点。在执行代码时,结果是观察到的气缸轻微倾斜90度 实际问题: 上述算法是用Fortran语言实现的。如果在圆柱体内,代码将检查笛卡尔网格中的点。以下为测试用例: 圆柱体在yz平面内与y轴成90度角。因此,方向向量$\vec{o}$是(0,1,0) 案例1: 方向向量直接指定为$\vec{o}=(0.0,1.0,0.0)$。这将产生$\theta=90的完美圆柱体$ 案例2: 方向向量是使用内部Fortran函数指定的,该函数具有双精度精度Fortran舍入错误,fortran,geometry,rounding,computational-geometry,Fortran,Geometry,Rounding,Computational Geometry,我有一个简单的代码,它用圆柱体包围的区域标记节点。在执行代码时,结果是观察到的气缸轻微倾斜90度 实际问题: 上述算法是用Fortran语言实现的。如果在圆柱体内,代码将检查笛卡尔网格中的点。以下为测试用例: 圆柱体在yz平面内与y轴成90度角。因此,方向向量$\vec{o}$是(0,1,0) 案例1: 方向向量直接指定为$\vec{o}=(0.0,1.0,0.0)$。这将产生$\theta=90的完美圆柱体$ 案例2: 方向向量是使用内部Fortran函数指定的,该函数具有双精度精度dsin
dsin
和dcos
,具有$\vec{o}=(0.0、\sin(\pi/2.0)、\cos(\pi/2.0))$,其中$\pi$值被分配了20多个有效小数点。由此产生的气缸会导致轻微倾斜
高亮显示的区域表示由于圆柱体相对于笛卡尔坐标轴倾斜而产生的额外材料。我也试过了,这也导致了同样的问题
这表明圆柱体的实际角度不是90度。谁能为这个问题提出有效的解决方案。我需要对任意角度使用内置三角函数,并寻找精确的单元标记方法
注:所有操作均以双精度执行
实际功能如下所示rk
是用值8
pure logical function in_particle(p,px,x)
type(md_particle_type),intent(in) :: p
real(kind=rk),intent(in) :: px(3),x(3)
real(kind=rk) :: r(3),rho(3),rop(2),ro2,rdiff,u
rop = particle_radii(p) ! (/R_orth,R_para/)
ro2 = rop(1)**2
rdiff = rop(2) - rop(1)
r = x-px
! Case 1:
! u = dot_product((/0.0_rk,-1.0_rk,0.0_rk/),r)
! rho = r-u*(/0.0_rk,-1.0_rk,0.0_rk/)
! Case 2:
u = dot_product((/0.0_rk,-dsin(pi/2.0_rk),dcos(pi/2.0_rk)/),r)
rho = r-u*(/0.0_rk,-dsin(pi/2.0_rk),dcos(pi/2.0_rk)/)
if((u.le.rdiff).and.(u.ge.-rdiff)) then
in_particle = dot_product(rho,rho) < ro2
else
in_particle = .false.
end if
end function in_particle
粒子(p,px,x)中的纯逻辑函数
类型(md_粒子类型),意图(in)::p
真实(种类=rk),意图(单位):px(3),x(3)
实际(种类=rk):r(3)、rho(3)、rop(2)、ro2、rdiff、u
rop=粒子半径(p)!(/R_orth,R_para/)
ro2=rop(1)**2
rdiff=rop(2)-rop(1)
r=x-px
! 案例1:
! u=点积((/0.0-1.0-0.0-r,0.0-r/),r)
! rho=r-u*(/0.0_-rk,-1.0_-rk,0.0_-rk/)
! 案例2:
u=点积(/0.0_-rk,-dsin(pi/2.0_-rk),dcos(pi/2.0_-rk)/),r)
rho=r-u*(/0.0_-rk,-dsin(pi/2.0_-rk),dcos(pi/2.0_-rk)/)
如果((u.le.rdiff.)和(u.ge.-rdiff)),则
in_粒子=点积(rho,rho)cos(pi/2)
不一定会给你精确的0,无论你进行多么精确的cos
计算,也不管你有多少位数的pi
,因为:
,作为无理数,当表示为FP数时,将包含多达1/2 ulp的错误;及pi
- IEEE-754标准不保证sin和cos四舍五入正确(甚至不实施)
sin(pi/2)
极有可能成为1,而不管精度和FP架构如何,这仅仅是因为sin
在1附近有一个很低的导数;对于单精度浮点,如果您在3e-4
的精确值pi/2
的范围内,则它应该为1。有问题的调用是cos
,它的精度非常高,大约为0,在邻域中的导数大约为-1
不过,我们这里讨论的是非常小的值。我认为真正加剧问题的是您正在进行的输入/输出测试,以及普通的FP舍入规则。我想,事实上,如果你将测试点偏移,比如说,栅格量子的四分之一,你会在体素化中看到所有的垂直直线(尽管它可能不是围绕短轴对称的)
另一种选择是,在进行点积之前,实际上放弃sin/cos计算的一些精度,从而有效地量化轴。cos(pi/2)
不一定会给你精确的0,无论你的计算多么精确,无论你有多少位pi
,因为:
,作为无理数,当表示为FP数时,将包含多达1/2 ulp的错误;及pi
- IEEE-754标准不保证sin和cos四舍五入正确(甚至不实施)
sin(pi/2)
极有可能成为1,而不管精度和FP架构如何,这仅仅是因为sin
在1附近有一个很低的导数;对于单精度浮点,如果您在3e-4
的精确值pi/2
的范围内,则它应该为1。有问题的调用是cos
,它的精度非常高,大约为0,在邻域中的导数大约为-1
不过,我们这里讨论的是非常小的值。我认为真正加剧问题的是您正在进行的输入/输出测试,以及普通的FP舍入规则。我想,事实上,如果你将测试点偏移,比如说,栅格量子的四分之一,你会在体素化中看到所有的垂直直线(尽管它可能不是围绕短轴对称的)
另一种选择是,在进行点积之前,实际放弃sin/cos计算中的一些精度,从而有效地量化轴。简短回答:创建一个公共角度(0,pi/6,pi/4,pi/3,pi/2,pi及其倍数)的
sin
和cos
表格,并仅计算不常见角度。原因