3

최근에 내 .f90 코드를 .f03으로 업데이트했습니다. 이전 버전에서는 각 반복마다 할당 및 할당 해제 (7 3D 배열 - 45x45x45)가 필요했기 때문에 속도 향상이 예상됩니다. do 루프 (총 4000 개). 파생 된 유형을 사용하여 시뮬레이션의 시작 부분에 이러한 배열을 할당하고 끝에 할당을 해제합니다. 나는 스피드 업을 볼 것이라고 생각했지만, 실제로는 상당히 느리게 실행 중이다. (23 분이 아닌 30 분).fortran 연산자 오버로드 : function 또는 subroutine

프로필러를 실행했는데 더하기/빼기/곱하기/나누기 연산자가 비교적 오래 걸리는 것처럼 보입니다. 표준 변화의 변화를 제외하고, 운영자는 내가 말할 수있는 유일한 차이점이 있습니다. 이 기능이 모든 작업 중에 필드 수량의 새로운 사본을 반환한다는 사실 때문인지 궁금합니다.

그래서 여기 내 질문입니다 : 함수를 서브 루틴으로 변경하면이 필드가 참조로 전달됩니다 (생각하니?). 또한 이것이 더 빠르고 더 선호된다면 왜이 모든 예제가 서브 루틴을 사용하는 대신 연산자 오버로딩을위한 함수를 보여줄 수 있습니까? 나는 뭔가를 놓친 것 같은 기분이 든다. 연산자 오버로딩과 기능에 대한

참고 :

http://www.mathcs.emory.edu/~cheung/Courses/561/Syllabus/6-Fortran/operators.html

http://research.physics.illinois.edu/ElectronicStructure/498-s97/comp_info/overload.html

https://web.stanford.edu/class/me200c/tutorial_90/13_extra.html

다음

https://www.ibm.com/developerworks/community/blogs/b10932b4-0edd-4e61-89f2-6e478ccba9aa/entry/object_oriented_fortran_does_fortran_support_operator_overloading55?lang=en

내 연산자 중 하나의 예 :

function vectorVectorDivide(f,g) result(q) 
     implicit none 
     type(vectorField),intent(in) :: f,g 
     type(vectorField) :: q 
     q%x = f%x/g%x; q%y = f%y/g%y; q%z = f%z/g%z 
     q%sx = f%sx; q%sy = f%sy; q%sz = f%sz 
    end function 

어떤 도움이나 정보도 크게 알려드립니다. 여기에 두 가지 질문이 있습니다

+0

예, 감사 – Charlie

답변

6

: 어떤 상황에서

  1. , 나는 함수 접근법을 통해 서브 루틴 방식을 사용하여 더 나은 성능을 얻을 수 있나요?
  2. 성능이 저하되면 왜 기능을 사용하고 싶습니까?

첫 번째 질문에 대해 중요한 점은 스스로 테스트하는 것이 가장 좋습니다. 특정 측면이 많이 있습니다.

그러나 나는 당신을 안내 할 수있는 어떤 것을 빠르게 노크했습니다. 이와

module test 

    implicit none 

    type t1 
    real, allocatable :: x(:) 
    end type t1 

contains 

    function div_fun(f,g) result(q) 
    type(t1), intent(in) :: f, g 
    type(t1) q 
    q%x = f%x/g%x 
    end function div_fun 

    subroutine div_sub1(f, g, q) 
    type(t1), intent(in) :: f, g 
    type(t1), intent(out) :: q 
    q%x = f%x/g%x 
    end subroutine div_sub1 

    subroutine div_sub2(f, g, q) 
    type(t1), intent(in) :: f, g 
    type(t1), intent(inout) :: q 
    q%x(:) = f%x/g%x 
    end subroutine div_sub2 

end module test 

, 나는 때때로 함수와 서브 루틴을 사용하여 사이에 유의 한 차이가 없음을 관찰하고, 때로는 있었다. 즉, 컴파일러, 플래그 등에 따라 다릅니다.

그러나 무슨 일이 일어나는지주의하는 것이 중요합니다.

결과에 할당이 필요하며 서브 루틴 div_sub1의 경우 intent(out) 인수에는 할당이 필요합니다. [함수 결과를 할당하면 나중에 추가됩니다.상기 할당이 재사용된다 div_sub2에서

(이하 "결과"인자이다 intent(inout)) 우리는 q%x(:)를 사용하여 자동으로 재 할당을 억제. 후자의 부분은 중요합니다. 컴파일러는 크기 조정의 필요 여부를 확인하기 위해 오버 헤드를 자주 겪습니다. 이 후반 부분은 q의 의도를 div_sub1에서 inout으로 변경하여 테스트 할 수 있습니다.

[이 div_sub2 접근 방식에는 크기가 변하지 않는다는 가정이 있습니다. 이것은 텍스트에 의해 뒷받침 된 것으로 보입니다.]

첫 번째 질문에 대해 결론을 내리면 : 직접 확인하십시오.하지만 파생 된 유형을 사용하여 할당을 단순히 "숨기고 있는지"궁금합니다. 매개 변수화 된 파생 유형을 사용하면 매우 다른 답변을 얻을 수 있습니다.

두 번째 질문과 관련하여 기능이 일반적으로 사용되는 이유는 무엇입니까? (당신이 요청했습니다 이전 질문) 질문 텍스트와 링크에서

q = div_fun(f,g) 
call div_sub2(f,g,q) ! Could be much faster 

난 당신이 / 연산자를 오버로드 무언가가 있다고 가정합니다 : 당신은 내가 매우 특별한 경우 검토 한주의 것 우리가이 이항 연산자로 사용할 수 있습니다로

q = f/g    ! Could be slower, but looks good. 
call div_sub2(f,g,q) 

을 허용

interface operator (/) 
    module procedure div_fun 
end interface 

(참조 포트 2008 7.1.5, 7.1.6 실행) 절차는 반드시 함수 여야합니다. 이 답변의 이전 개정판에 대한 귀하의 의견에 대한 응답으로

div_sub1 및 div_sub2 이진 연산자는 div_fun과 동일하지 않습니까?

적어도 포트란이 2 진수 연산자 (위와 같은 링크)로 정의하는 점에서 대답은 "아니오"입니다. [div_fun 자체가 이진 연산자가 아니기 때문에 함수와 함수를 결합한 일반 인터페이스의 조합]

이진 연산을 사용하면 식의 일부가 될 수 있습니다.

q = q + alpha*(f/g)    ! Very neat 
call div_sub2(f,g,temp1) 
call mult_sub(alpha, temp1, temp2) 
call add_sub(q, temp2, temp3) 
call assign_sub(q, temp3) 

서브 루틴을 사용하면 약간 지저분해질 수 있습니다. 위의 예제는 "적절한"측면 (또는 전문 서브 루틴)을 처리하여 약간 정돈 될 수 있지만, 이것이 최종 점이됩니다. 함수 결과가 (할당 포함) 나중에 사용하기 전에 완전히 평가되기 때문에 우리는 두 번째 질문에 대한 결론적으로

f = f/g ! or f=div_fun(f,g) 
call div_sub2(f,g,f) ! Beware aliasing 

같은 상황이 : 성능이 전부는 아니예요.

[당신은 표준 준수를 적용하면/표시하기 위해 .f90.f03 파일 접미사를 사용하는 것을 의미하는 경우 마지막으로, 당신은 사람들이 그것에 대해 어떻게 생각하는지 볼 수 있습니다.]

+0

할당 가능한 배열, I 이러한 다양한 시나리오를 테스트하여 성능이 어떻게 변하는 지 확인하십시오. 왜 그렇게 많은 소스가 함수 접근법을 사용하는 것인가에 대한 의견? 다시 한 번 감사드립니다! – Charlie

+0

나는 나의 마지막 코멘트에서 더 구체적이어야했다."왜 그렇게 많은 소스가 서브 루틴 접근 방식 대신 함수 접근 방식을 사용하는 것 같은지에 대한 의견을 말해야합니다." 당신의 대답이 여전히 적용된다면, 나는 혼란 스럽다. div_fub1과 div_sub2 이원 연산자가 div_fun과 같지 않은가? – Charlie

+0

@Charlie 여기서 누락 된 것은 실제로 하나뿐 아니라 두 가지 연산을 수행한다는 것입니다. 'f'를 'g'로 나누고 결과를'q '로 지정하십시오. 'div_fun'과'div_sub1'도 같은 일을하지만 어떻게 오버로드합니까? '/'를'div_sub1'로 오버로드하면 컴파일러에게 세 개의 인수를 취하는 프로 시저를 사용하여'f/g'를 수행 할 것을 요청하지만'f'와'g' 두 개만 있습니다. 당신이 정말로 요구하는 것은'q = div_sub (f, g)'이고,'div_sub'는 이것이 합법적이어야 함을위한 함수 여야합니다. – PetrH