2016-09-15 29 views
4

ODEシステムのソリューションで可能な限り高い精度を達成しようとしているいくつかの長期的なシミュレーションを行っています。私は、倍精度(128ビット)の精度計算と倍精度(64ビット)精度のどちらの時間がかかるかを調べようとしています。私は、少し周りググと、いくつかのそれについての意見を見た:いくつかは、それが4倍の時間がかかりますと言う、他人60-70回...だから私は自分の手に掲げる事項を取ることを決めたと、私はシンプルなFortranのベンチマークプログラムを書いた:4倍の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. 

何かがここで起こっている必要があります。私の推測では、sqrtgfortranで計算され、4倍精度計算では実装されていない可能性があります。これはsincosの場合ではないかもしれませんが、なぜ基本操作は4倍精度で7.6倍遅くなりますが、三角関数では2倍だけ減速しますか?三角関数に使用されるアルゴリズムがクワッドと倍精度で同じであれば、CPU時間が7倍も増加することが予想されます。

は64ビットと比較して、128ビットの精度が使用される科学計算の平均減速は何ですか?

私は3.50GHz @インテルi7-4771でこれを実行しています。

+4

マルチコアシステムでは、CPU_TIMEを使用しないでください。 1つのコアで開始時間をとり、別のコアで終了時間になることがあります。これらの時間は相関がないので、何かを得るかもしれません。 'system_clock'を使うことでこの問題は解決します。 –

+1

https://stackoverflow.com/questions/6878246/fortran-intrinsic- [ここ]((https://stackoverflow.com/questions/25465101/fortran-parallel-programming/25465290#25465290)と[ここ]、参照してください。タイミング・ルーチン - これは、より良い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'に設定し、もう一方は' 2'の平方根を計算します。 'sqrt(2._qp)'はコンパイル時に計算することができます。 –

+0

また、元の質問に対するコメントまたは回答ですか? –

+0

コードがループして、結果が計算を繰り返すことになります。sqrt(2.0) –