在 Fortran 中是否有快速向上/向下舍入的方法?
由于正双数的位表示的线性顺序,可以如下实现舍入。
pinf
并且ninf
是分别为 +/- 无穷大的全局常数
function roundup(x)
double precision ,intent(in) :: x
double precision :: roundup
if (isnan(x))then
roundup = pinf
return
end if
if (x==pinf)then
roundup = pinf
return
end if
if (x==ninf)then
roundup = ninf
return
end if
if (x>0)then
roundup = transfer((transfer(x,1_8)+1_8),1d0)
else if (x<0) then
roundup = transfer((transfer(x,1_8)-1_8),1d0)
else
if (transfer(x,1_8)==Z'0000000000000000')then
roundup = transfer((transfer(x,1_8)+1_8),1d0)
else
roundup = transfer((transfer(-x,1_8)+1_8),1d0)
end if
end if
end function roundup
我觉得这不是最好的方法,因为它很慢,但它几乎只使用位操作。
另一种方法是使用乘法和一些 epsilon
eps = epsilon (1d0)
function roundup2(x)
double precision ,intent(in) :: x
double precision :: roundup2
if (isnan(x)) then
roundup2 = pinf
return
else if (x>=eps) then
roundup2 = x*(1d0+eps)
else if (x<=-eps) then
roundup2 = x*(1d0-eps)
else
roundup2 = eps
end if
end function roundup2
对于某些x
两个函数返回相同的结果 (1d0, 158d0),对于某些不返回 (0.1d0, 15d0)。
第一个函数更准确,但比第二个函数慢 3.6 倍(10^9 轮测试中 11.1 对 3.0 秒)
print * ,x,y,abs(x-y)
do i = 1, 1000000000
x = roundup(x)
!y = roundup2(y)
end do
print * ,x,y,abs(x-y)
在不检查 NaN/Infinities 的情况下,第一个功能测试需要 8.5 秒 (-20%)。
我真的很难使用圆形功能,并且在程序配置文件中需要很多时间。是否有跨平台的方法可以更快地进行舍入而不丢失精度?
更新
这个问题怀疑当时的综述和四舍五入调用没有能力重新排序。我没有提到四舍五入以保持话题简短。
提示:第一个函数使用两个transfer
函数和一个加法。在第二种情况下,它比一次乘法和一次加法要慢。当它对数字的位没有任何作用时,为什么传输成本如此之高?是否可以用更快的函数替换传输或完全避免添加调用?