Saya memiliki fungsi numerik yang f(x, y)
mengembalikan angka floating point ganda yang mengimplementasikan beberapa rumus dan saya ingin memeriksa apakah itu benar terhadap ekspresi analitik untuk semua kombinasi parameter x
dan y
saya tertarik. Apa cara yang tepat untuk membandingkan yang dihitung dan dihitung angka floating point analitik?
Katakanlah dua angka itu adalah a
dan b
. Sejauh ini saya telah memastikan bahwa kedua kesalahan absolut ( abs(a-b) < eps
) dan juga relatif ( abs(a-b)/max(abs(a), abs(b)) < eps
) kurang dari eps. Dengan begitu ia akan menangkap ketidakakuratan numerik bahkan jika angkanya sekitar 1e-20.
Namun, hari ini saya menemukan masalah, nilai numerik a
dan nilai analitiknya b
adalah:
In [47]: a
Out[47]: 5.9781943146790832e-322
In [48]: b
Out[48]: 6.0276008792632078e-322
In [50]: abs(a-b)
Out[50]: 4.9406564584124654e-324
In [52]: abs(a-b) / max(a, b)
Out[52]: 0.0081967213114754103
Jadi kesalahan absolut [50] adalah (jelas) kecil, tetapi kesalahan relatif [52] besar. Jadi saya pikir saya punya bug di program saya. Dengan men-debug, saya menyadari, bahwa angka-angka ini tidak normal . Karena itu, saya menulis rutin berikut untuk melakukan perbandingan relatif yang tepat:
real(dp) elemental function rel_error(a, b) result(r)
real(dp), intent(in) :: a, b
real(dp) :: m, d
d = abs(a-b)
m = max(abs(a), abs(b))
if (d < tiny(1._dp)) then
r = 0
else
r = d / m
end if
end function
Di mana tiny(1._dp)
mengembalikan 2.22507385850720138E-308 di komputer saya. Sekarang semuanya berfungsi dan saya hanya mendapatkan 0 sebagai kesalahan relatif dan semuanya baik-baik saja. Secara khusus, kesalahan relatif di atas [52] salah, itu hanya disebabkan oleh kurang akuratnya angka denormal. Apakah implementasi rel_error
fungsi saya benar? Haruskah saya memeriksa yang abs(a-b)
kurang dari kecil (= tidak normal), dan mengembalikan 0? Atau haruskah saya memeriksa beberapa kombinasi lain, seperti
max(abs(a), abs(b))
?
Saya hanya ingin tahu apa cara yang "tepat" itu.
exp(log_gamma(m+0.5_dp) - (m+0.5_dp)*log(t)) / 2
untuk m = 234, t = 2000. Ini menjadi nol dengan cepat saat saya bertambahm
. Semua saya ingin memastikan bahwa rutin numerik saya mengembalikan angka "benar" (untuk mengembalikan nol juga baik-baik saja) ke setidaknya 12 digit signifikan. Jadi, jika perhitungan mengembalikan angka yang tidak normal, maka itu hanya nol, dan seharusnya tidak ada masalah. Jadi, hanya perbandingan rutin harus kuat terhadap ini.