2016-09-15 4 views
4

ODE 시스템의 솔루션에서 최대한의 정확도를 얻기 위해 장기간 시뮬레이션을하고 있습니다. 4 배 (128 비트) 정밀도 계산과 2 배 (64 비트) 정밀도를 비교하는 시간을 확인하려고합니다. 몇 번 봤는데 몇 가지 의견을 봤어 : 일부는 4 배 더 오래 걸릴거야, 다른 말은 60-70 배 걸릴거야. 그래서 내 자신의 문제를 해결하기로 결심했다. 간단한 포트란 벤치 마크 프로그램을 작성했다.CPU 시간이 4 배 대 배정

전형적인 실행의
program QUAD_TEST 

implicit none 

integer,parameter :: dp = selected_int_kind(15) 
integer,parameter :: qp = selected_int_kind(33) 

integer :: cstart_dp,cend_dp,cstart_qp,cend_qp,crate 
real  :: time_dp,time_qp 
real(dp) :: sum_dp,sqrt_dp,pi_dp,mone_dp,zero_dp 
real(qp) :: sum_qp,sqrt_qp,pi_qp,mone_qp,zero_qp 
integer :: i 

! ============================================================================== 

! == TEST 1. ELEMENTARY OPERATIONS == 
sum_dp = 1._dp 
sum_qp = 1._qp 
call SYSTEM_CLOCK(count_rate=crate) 

write(*,*) 'Testing elementary operations...' 

call SYSTEM_CLOCK(count=cstart_dp) 
do i=1,50000000 
    sum_dp = sum_dp - 1._dp 
    sum_dp = sum_dp + 1._dp 
    sum_dp = sum_dp*2._dp 
    sum_dp = sum_dp/2._dp 
end do 
call SYSTEM_CLOCK(count=cend_dp) 
time_dp = real(cend_dp - cstart_dp)/real(crate) 
write(*,*) 'DP sum: ',sum_dp 
write(*,*) 'DP time: ',time_dp,' seconds' 

call SYSTEM_CLOCK(count=cstart_qp) 
do i=1,50000000 
    sum_qp = sum_qp - 1._qp 
    sum_qp = sum_qp + 1._qp 
    sum_qp = sum_qp*2._qp 
    sum_qp = sum_qp/2._qp 
end do 
call SYSTEM_CLOCK(count=cend_qp) 
time_qp = real(cend_qp - cstart_qp)/real(crate) 
write(*,*) 'QP sum: ',sum_qp 
write(*,*) 'QP time: ',time_qp,' seconds' 
write(*,*) 
write(*,*) 'DP is ',time_qp/time_dp,' times faster.' 
write(*,*) 

! == TEST 2. SQUARE ROOT == 
sqrt_dp = 2._dp 
sqrt_qp = 2._qp 

write(*,*) 'Testing square root ...' 

call SYSTEM_CLOCK(count=cstart_dp) 
do i = 1,10000000 
    sqrt_dp = sqrt(sqrt_dp) 
    sqrt_dp = 2._dp 
end do 
call SYSTEM_CLOCK(count=cend_dp) 
time_dp = real(cend_dp - cstart_dp)/real(crate) 
write(*,*) 'DP sqrt: ',sqrt_dp 
write(*,*) 'DP time: ',time_dp,' seconds' 

call SYSTEM_CLOCK(count=cstart_qp) 
do i = 1,10000000 
    sqrt_qp = sqrt(sqrt_qp) 
    sqrt_qp = 2._qp 
end do 
call SYSTEM_CLOCK(count=cend_qp) 
time_qp = real(cend_qp - cstart_qp)/real(crate) 
write(*,*) 'QP sqrt: ',sqrt_qp 
write(*,*) 'QP time: ',time_qp,' seconds' 
write(*,*) 
write(*,*) 'DP is ',time_qp/time_dp,' times faster.' 
write(*,*) 

! == TEST 3. TRIGONOMETRIC FUNCTIONS == 
pi_dp = acos(-1._dp); mone_dp = 1._dp; zero_dp = 0._dp 
pi_qp = acos(-1._qp); mone_qp = 1._qp; zero_qp = 0._qp 

write(*,*) 'Testing trigonometric functions ...' 

call SYSTEM_CLOCK(count=cstart_dp) 
do i = 1,10000000 
    mone_dp = cos(pi_dp) 
    zero_dp = sin(pi_dp) 
end do 
call SYSTEM_CLOCK(count=cend_dp) 
time_dp = real(cend_dp - cstart_dp)/real(crate) 
write(*,*) 'DP cos: ',mone_dp 
write(*,*) 'DP sin: ',zero_dp 
write(*,*) 'DP time: ',time_dp,' seconds' 

call SYSTEM_CLOCK(count=cstart_qp) 
do i = 1,10000000 
    mone_qp = cos(pi_qp) 
    zero_qp = sin(pi_qp) 
end do 
call SYSTEM_CLOCK(count=cend_qp) 
time_qp = real(cend_qp - cstart_qp)/real(crate) 
write(*,*) 'QP cos: ',mone_qp 
write(*,*) 'QP sin: ',zero_qp 
write(*,*) 'QP time: ',time_qp,' seconds' 
write(*,*) 
write(*,*) 'DP is ',time_qp/time_dp,' times faster.' 
write(*,*) 

end program QUAD_TEST 

결과, 어떤 최적화 플래그없이, gfortran 4.8.4로 컴파일 후 :

Testing elementary operations... 
DP sum: 1.0000000000000000  
DP time: 0.572000027  seconds 
QP sum: 1.00000000000000000000000000000000000  
QP time: 4.32299995  seconds 

DP is 7.55769205  times faster. 

Testing square root ... 
DP sqrt: 2.0000000000000000  
DP time: 5.20000011E-02 seconds 
QP sqrt: 2.00000000000000000000000000000000000  
QP time: 2.60700011  seconds 

DP is 50.1346169  times faster. 

Testing trigonometric functions ... 
DP cos: -1.0000000000000000  
DP sin: 1.2246467991473532E-016 
DP time: 2.79600000  seconds 
QP cos: -1.00000000000000000000000000000000000  
QP sin: 8.67181013E-0035 
QP time: 5.90199995  seconds 

DP is 2.11087275  times faster. 

뭔가 일이 일어나고해야합니다. 내 생각에 sqrt은 최적화 된 알고리즘을 통해 gfortran으로 계산됩니다. 이는 아마도 4 배 정밀도 계산을 위해 구현되지 않았을 것입니다. sincos의 경우는 그렇지 않을 수 있지만 기본 작동은 왜 4 배 정밀도에서 7.6 배 느려지는 반면 삼각 함수에서는 2 배만큼 느려 집니까? 삼각 함수에 사용 된 알고리즘이 쿼드 및 배정도에서 동일하면 CPU 시간이 7 배 증가 할 것으로 예상됩니다.

64 비트에 비해 128 비트 정밀도를 사용하면 과학 계산의 평균 속도가 느려 집니까?

저는 인텔 i7-4771 @ 3.50GHz에서 실행하고 있습니다.

+4

멀티 코어 시스템에서 'CPU_TIME'을 사용하지 마십시오. 한 코어에서 시작 시간을, 다른 코어에서 종료 시간을 가져갈 수 있습니다. 이 시간은 상관 관계가 없으므로 아무 것도 얻을 수 없습니다. 'system_clock'을 사용하면이 문제가 해결됩니다. –

+1

[여기] (https://stackoverflow.com/questions/25465101/fortran-parallel-programming/25465290#25465290) 및 [여기] (https://stackoverflow.com/questions/6878246/fortran-intrinsic- 타이밍 - 루틴 - 어느 것이 더 나은 cpu-time-or-system-clock인지). –

+0

Thanks @ AlexanderVogt, 나는 SYSTEM_CLOCK을 사용하기 위해 게시물을 편집했다. – LeWavite

답변

5

더 답변보다 확장 된 의견,하지만 ...

현재 CPU는 배정 밀도 부동 소수점 연산을위한 하드웨어 가속을 많이 제공합니다. 일부는 확장 정밀도를위한 시설을 제공하기도합니다. 그 이상으로, 당신은 상당히 느린 소프트웨어 구현으로 제한됩니다.

그러나 이러한 속도 저하의 정확한 요인은 일반적인 경우 예측하기가 거의 불가능합니다. CPU (예 : 가속 기능)와 소프트웨어 스택에 따라 다릅니다. 배정 밀도의 경우 일반적으로 네 배 정밀도와 다른 수학 라이브러리를 사용하며 기본 연산에 대해 서로 다른 알고리즘을 사용할 수 있습니다.

동일한 알고리즘을 사용하는 특정 하드웨어의 특정 연산/알고리즘에 대해서는 숫자를 얻을 수 있지만 이는 사실이 아닙니다.

sqrt_qp = sqrt(sqrt_qp) 
sqrt_qp = 2._qp 

sqrt_qp = sqrt(2._qp) 

에 계산이 빨라집니다 :

0

그것은 당신이 변경하는 경우주의하는 것이 재미 있어요!

+0

무엇?코드의 두 부분은 완전히 다른 것을합니다! 먼저 변수를 '2'로 설정하고 다른 변수는 '2'의 제곱근을 계산합니다. 그리고'sqrt (2._qp)'는 컴파일시에 계산 될 수있다. –

+0

또한 원래의 질문에 대한 답변입니까? –

+0

코드가 반복되어 결과가 반복됩니다. sqrt (2.0) –

관련 문제