2016-09-15 78 views
4

我正在做一些長期模擬,我試圖在ODE系統的解決方案中實現最高的準確性。我試圖找出四倍(128位)精度計算需要多少時間才能達到雙倍(64位)精度。我搜索了一下,並看到了一些有關它的觀點:有人說它將需要4倍的時間,其他人需要60-70次...因此,我決定親自動手,並編寫了一個簡單的Fortran基準程序:CPU時間四倍與雙精度

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一起計算,該算法可能還沒有用於四倍精度計算。這可能不是sincos的情況,但爲什麼基本操作的四倍精度要慢7.6倍,而對於三角函數,事情只能減慢2倍?如果用於三角函數的算法對於四倍和雙精度的算法是相同的,那麼我預計他們的CPU時間也會增加七倍。

使用128位精度時,與64位相比,科學計算的平均減速度是多少?

我在Intel i7-4771 @ 3.50GHz上運行這個。

+4

請勿在多核系統上使用'CPU_TIME'。您可能最終將一個核心的開始時間和另一個核心的結束時間考慮在內。由於這些時間不相關,你可能會得到任何東西。使用'system_clock'解決了這個問題。 –

+1

請參閱[此處](https://stackoverflow.com/questions/25465101/fortran-parallel-programming/25465290#25465290)和[here](https://stackoverflow.com/questions/6878246/fortran-intrinsic-定時例程 - 這就是更好-CPU時間 - 或系統時鐘)。 –

+0

感謝@AlexanderVogt,我編輯帖子以使用SYSTEM_CLOCK。 – LeWavite

回答

5

超過一個答案延長髮表評論,但...

當前CPU的雙精度浮點運算提供了大量的硬件加速。有些甚至提供擴展精度的設施。 除此之外,您僅限於(如您注意的)相當慢的軟件實現。

但是,在一般情況下,這種減速的確切因素幾乎無法預測。 它取決於您的CPU(例如,它內置了哪種加速度)以及軟件堆棧。 對於雙精度,通常使用不同的數學庫,而不是四倍精度,這些可能會對基本操作使用不同的算法。

對於使用相同算法的給定硬件上的特定操作/算法,您可能可以派生一個數字,但這肯定不是普遍適用的。

0

有趣的是要注意,如果你改變:

sqrt_qp = sqrt(sqrt_qp) 
sqrt_qp = 2._qp 

sqrt_qp = sqrt(2._qp) 

計算會更快!

+0

什麼?你的兩段代碼做了完全不同的事情!首先將變量設置爲「2」,另一個計算「2」的平方根。 'sqrt(2._qp)'可以在編譯時計算。 –

+0

此外,這只是一個評論或原始問題的答案? –

+0

該代碼是在一個循環中,結果是重複計算sqrt(2.0) –