Fortran四舍五入错误

时间:2016-06-18 13:45:56

标签: 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: 使用具有双精度精度dsindcos的内部Fortran函数指定方向向量,其中$ \ vec {o} =(0.0,\ sin(\ pi / 2.0),\ cos(\ pi / 2.0) ))$,$ \ pi $值分配超过20个有效小数点。产生的圆柱体会产生轻微的倾斜。

突出显示的区域表示由于圆柱相对于笛卡尔坐标轴的倾斜而产生的额外材料。我也试过architecture specific maximum precision "pi" value.这也导致同样的问题。

这表示圆柱体的实际角度不是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

注意:三角函数在代码内完成,可以更好地解释问题。但是,原始代码从用户读取矢量形式的方向。然后将此信息转换为粒子 - 粒子碰撞操作的四元数。在将四元数转换回方向向量时,此错误甚至会更加放大。即使在碰撞开始之前,圆柱的方向也会被2个格子单元迷失方向。

2 个答案:

答案 0 :(得分:4)

cos(pi/2)不一定会给你完全0,无论你进行cos计算有多精确,无论你有pi多少位数,因为:< / p>

  • pi,作为无理数,当表示为FP编号时,将包含高达1/2 ulp的错误;和
  • sincos不保证IEEE-754标准无法正确舍入(甚至实施)。

现在,无论精度和FP架构如何,sin(pi/2) 极有可能出现为1,只是因为sin具有1左右的低导数;对于单精度浮点数,如果你在3e-4的精确值的大约pi/2内的任何地方,它应该是1。有问题的调用是cos,它具有大约0的精度和附近约-1的导数。

尽管如此,我们仍然在谈论极小的价值观。我认为这里真正能够解决问题的是你正在进行的输入/输出测试,以及普通的FP舍入规则。事实上,我猜想,如果你将你的测试点偏差,比如四分之一的网格量,你会看到你体素化中的所有直线垂直(尽管它可能不是围绕短轴对称的) )。

另一种选择是在进行点积之前实际丢弃sin / cos计算中的一些精度,有效地量化轴。

答案 1 :(得分:3)

简答:创建sincos个共同角度(0,pi / 6,pi / 4,pi / 3,pi / 2,pi及其倍数)的表格并计算仅适用于不常见的角度。原因是大多数人都会容忍不常见角度的错误,而普通角度的错误可能不会被容忍。

说明: 因为浮点计算不精确(这是它的本质),所以有时需要在代码的准确性和可读性之间进行一些折衷。

这样做的一种方法是避免计算确切知道的东西。要做到这一点,你可以检查角度的值,只有当它不是一个明显的角度时才进行实际计算。例如,角度0,90,180和270度具有明显的sincos值。更一般地,cossin共同角度(0,pi / 6,pi / 4,pi / 3,pi / 2,pi及其倍数)是确切已知的(即使它们是无理数)。

相关问题