Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/fortran/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
fortran中的快速向上/向下双进位?_Fortran_Ieee 754_Rounding Error - Fatal编程技术网

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

在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
对于某些
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更快,我无法确定您的机器上发生了什么,但我可以说两件事:

  • roundup2中的加法可能被优化了(如果eps是一个参数?),所以实际上只有一个乘法
  • 如果传输真的有任何作用,那么很容易就会明显地降低函数的速度,因为函数本身很短。如果传输只是制作x的多余副本,那么这可能是真的

  • 谢谢你的推荐,但它不适合我的需要。我不能重新安排批量操作。可能有一些关于位函数的技巧?你不必大量使用它们。为什么不尝试编写一个使用标准功能的函数,看看它是如何为您工作的呢?我认为它必须比你提出的其他事情更快。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)