2013-08-27 6 views
2

Fortran에서 반올림/빨리 감기 할 수있는 빠른 방법이 있습니까?포트란에서 빠른 라운드 업/다운 더블?

양수의 비트 표현의 선형 순서 때문에 다음과 같이 반올림을 구현할 수 있습니다.

pinfninf 나는 그것이 느린이기 때문에 그렇게 할 수있는 가장 좋은 방법이 아니다 느낄

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 

각각 무한대 +/-하는 전역 상수하지만, 거의 유일한 비트 연산을 사용합니다. 일부는하지 (0.1d0, 15d0)을 수행하기위한

또 다른 방법

이 같은 결과 (1D0, 158d0)를 곱셈과 일부 x 두 함수의 일부 엡실론 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 

을 반환 사용하고 있습니다.

첫번째 기능은 더 정확하지만,이 NaN 없음 수표

print * ,x,y,abs(x-y) 
    do i = 1, 1000000000 
     x = roundup(x) 
     !y = roundup2(y) 
    end do 
    print * ,x,y,abs(x-y) 

(10^9 발사 시험 11.1 VS 3.0 초) 초 보다 약 3.6 배 느리다/무한대 제 1 기능 테스트는 소요 8.5 초 (-20 %).

난 둥근 기능을 정말 열심히 사용하며 프로그램의 프로필에서 많은 시간이 걸립니다. 정밀도가 떨어지지 않고 더 빨리 라운드 할 수있는 크로스 플랫폼 방식이 있습니까?

업데이트

문제는 그 순서를 할 수없는 능력을 가진시 검거 및 ROUNDDOWN의 호출을 의심. 나는 주제를 짧게 유지하기 위해 라운드 다운을 언급하지 않았다.

힌트 : 첫 번째 기능은 두 개의 transfer 기능과 하나의 기능을 사용합니다. 그리고 두 번째 경우에는 하나의 곱셈과 하나의 덧셈보다 느립니다. 숫자를 조금이라도 옮기지 않으면 비용이 많이 들지 않는 이유는 무엇입니까? 더 빠른 기능으로 전송을 대체하거나 추가 호출을 전혀 피할 수 있습니까?

+0

nint를 사용해 보셨습니까? – cup

+0

int가 아닌 가장 가까운 대표 값으로 "round"해야합니다. 제목은 다소 오도 될 수 있지만 신체에서 분명합니다. – Sergei

답변

2

내가하고 싶은 것을 정확하게 이해하고 있다면, "가장 가까운"내장 함수가 +/- 무한대를 인수로 사용하면 원하는 것을 수행하지 않습니까? 컴파일러는 괜찮은 성능이 구현하는 경우

http://gcc.gnu.org/onlinedocs/gfortran/NEAREST.html#NEAREST

이, 작동 할 수 있습니다.NaN이 Inf로 반올림되도록하려면 래퍼에 NaN을 추가해야합니다.

roundup2가 빠른 이유에 관해서는, 나는 당신의 컴퓨터에 무슨 일이 일어나고 있는지 확실히 알 수는 없지만, 나는 두 가지를 말할 수있다 : EPS 인 경우 roundup2의 추가는 아마 (교체 아웃 최적화되어

    1. 매개 변수?), 정말 곱셈 만 있습니다.
    2. 전송이 실제로 아무것도 수행하지 않으면 기능 자체가 너무 짧기 때문에 기능을 쉽게 느려질 수 있습니다. 전송이 x의 불필요한 사본을 만들고있는 경우에도 마찬가지 일 수 있습니다.
  • +0

    감사합니다. NEAREST는 평범한 복식으로 잘 작동하지만 gcc를 사용하는 컴퓨터에서 처음으로 '검거 (roundup)'보다 3 배 더 느립니다. – Sergei

    +0

    그것은 당신의 것보다 훨씬 느리다는 것이 이상합니다. [nextafter] (http://svn.open64.net/svnroot/open64/trunk/osprey/libacml_mv/src/nextafter.c)와 비슷한 구현을 사용하고있을 가능성이 큽니다. 그 자체가 당신의 첫 번째 검거와 매우 비슷합니다. –

    3

    Fortran 표준 IEEE 부동 소수점 내장 모듈 (IEEE_ARITHMETIC, IEEE_FEATURES, IEEE_EXCEPTIONS)을 살펴 보는 것이 좋습니다. 이것들은 IEEE_SET_ROUNDING_MODE를 제공합니다.이 곳에서 후속 작업을위한 반올림 모드를 설정할 수 있습니다. 이상적으로 IEEE_GET_ROUNDING_MODE를 사용하여 현재 모드를 가져 와서 저장하고 새 모드를 설정 한 다음 작업을 수행 한 다음 모드를 복원하십시오.

    일부주의 사항 - 프로세서 반올림 모드를 변경하는 것은 느린 작업이지만, 한 번 수행 한 다음 많은 라운드를 수행하면 승리합니다. 현재의 모든 Fortran 컴파일러가 IEEE 내장 모듈을 지원하는 것은 아니지만 가장 합리적인 것들이 있어야합니다. 컴파일러에게 IEEE 환경에서 놀고 있다고 말할 필요가 있습니다. 인텔 포트란의 경우 "-fp-model strict"를 사용하십시오.

    +0

    추천 해 주셔서 감사합니다.하지만 내 필요에 맞는 것은 아닙니다. 대량 작업을 수행하려면 라운드 작업을 재정렬 할 수 없습니다. 비트 기능을 가진 트릭이있을 수 있습니까? – Sergei

    +0

    대량으로 처리하지 않아도됩니다. 왜 표준 기능을 사용하는 함수를 작성하고 그것이 어떻게 작동하는지보십시오. 나는 당신이 제안한 다른 것들보다 빠를 것이라고 생각합니다. FP 값의 비트 조작은 매우 까다 롭습니다. 그렇게하는 코드를 작성하고 수정 한 버그를 알고 있어야합니다. –

    +0

    검거와 라운드 다운을 동시에 사용해야합니다. 언급 한 것처럼 반올림 모드를 변경하는 것은 비용이 많이 듭니다. 나는 그것을 할 수 없다. – Sergei