fortran中的快速向上/向下双进位?
在Fortran中是否有快速的向上/向下取整方法 由于正双数的位表示的线性顺序,可以实现如下舍入fortran中的快速向上/向下双进位?,fortran,ieee-754,rounding-error,Fortran,Ieee 754,Rounding Error,在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==pi
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
对于某些x
函数,两个函数返回相同的结果(1d0,158d0),而对于某些不返回相同的结果(0.1d0,15d0)
第一个函数更精确,但比第二个函数慢3.6倍
(10^9轮测试中,11.1秒对3.0秒)
在不检查NaN/无穷大的情况下,第一次功能测试需要8.5秒(-20%)
我使用圆函数真的很难,它需要在程序的配置文件很多时间。有没有跨平台的方法可以在不降低精度的情况下更快地转弯
更新
这个问题怀疑当时的综述和综述调用,而没有能力对它们进行重新排序。我并没有提到总结,以保持话题简短
提示:
第一个函数使用两个
transfer
函数和一个adding函数。它比第二种情况下的乘法和加法慢。为什么传输成本如此之高,而它不做任何与数字的位?有没有可能用更快的函数来代替传输,或者根本避免添加调用?我建议您查看Fortran标准IEEE浮点内部模块(IEEE_算法、IEEE_功能、IEEE_例外)。它们提供IEEE_设置_舍入_模式,您可以在其中为后续操作设置舍入模式。理想情况下,您应该使用IEEE_GET_ROUNDING_MODE获取当前模式并保存它,设置新模式,执行操作,然后恢复模式
一些注意事项-更改处理器舍入模式本身是一个缓慢的操作,但如果您只执行一次,然后执行多次舍入,这将是一个胜利。并非所有当前的Fortran编译器都支持IEEE内部模块,但最合理的编译器应该支持。您可能需要告诉编译器您正在使用IEEE环境-对于英特尔Fortran,请使用“-fp model strict”。如果我正确理解您想要做什么,如果您将+/-无穷大作为参数,那么“最近的”内禀函数不就是您想要的吗 如果编译器以良好的性能实现这一点,这可能会起作用。如果希望NaN取整为Inf,则必须将其添加到包装器中 至于为什么roundup2更快,我无法确定您的机器上发生了什么,但我可以说两件事:
谢谢你的推荐,但它不适合我的需要。我不能重新安排批量操作。可能有一些关于位函数的技巧?你不必大量使用它们。为什么不尝试编写一个使用标准功能的函数,看看它是如何为您工作的呢?我认为它必须比你提出的其他事情更快。FP值的位操作非常棘手-我应该知道,因为我已经编写了(并修复了其中的错误)这样做的代码。我需要同时使用roundup和rounddown。正如您所提到的,更改舍入模式非常昂贵。我做不到。你试过使用nint吗?我需要“四舍五入”到最接近的代表性双精度而不是int。标题可能有点误导,但从正文中可以清楚地看到。谢谢,最近的双精度很好地适用于通常的双精度,但它甚至比我使用gcc的机器上的第一个
roundup
慢了三倍。奇怪的是,它比你的机器慢得多,因为它可能使用类似于的实现,它本身非常类似于你的第一个roundup。
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
print * ,x,y,abs(x-y)
do i = 1, 1000000000
x = roundup(x)
!y = roundup2(y)
end do
print * ,x,y,abs(x-y)