Mengapa GHCi memberikan jawaban yang salah di bawah?
GHCi
λ> ((-20.24373193905347)^12)^2 - ((-20.24373193905347)^24)
4.503599627370496e15
Python3
>>> ((-20.24373193905347)**12)**2 - ((-20.24373193905347)**24)
0.0
UPDATE Saya akan mengimplementasikan fungsi Haskell (^) sebagai berikut.
powerXY :: Double -> Int -> Double
powerXY x 0 = 1
powerXY x y
| y < 0 = powerXY (1/x) (-y)
| otherwise =
let z = powerXY x (y `div` 2)
in if odd y then z*z*x else z*z
main = do
let x = -20.24373193905347
print $ powerXY (powerXY x 12) 2 - powerXY x 24 -- 0
print $ ((x^12)^2) - (x ^ 24) -- 4.503599627370496e15
Meskipun versi saya tidak tampak lebih benar daripada yang disediakan di bawah ini oleh @WillemVanOnsem, anehnya memberikan jawaban yang benar untuk kasus khusus ini setidaknya.
Python serupa.
def pw(x, y):
if y < 0:
return pw(1/x, -y)
if y == 0:
return 1
z = pw(x, y//2)
if y % 2 == 1:
return z*z*x
else:
return z*z
# prints 0.0
print(pw(pw(-20.24373193905347, 12), 2) - pw(-20.24373193905347, 24))
haskell
floating-point
ghc
ghci
Bung acak
sumber
sumber
a^24
kira-kira2.2437e31
, dan dengan demikian ada kesalahan pembulatan yang menghasilkan ini.2.243746917640863e31 - 2.2437469176408626e31
yang memiliki kesalahan pembulatan kecil yang akan diperkuat. Sepertinya masalah pembatalan.Jawaban:
Jawaban singkat : ada perbedaan antara
(^) :: (Num a, Integral b) => a -> b -> a
dan(**) :: Floating a => a -> a -> a
.The
(^)
fungsi bekerja hanya pada eksponen terpisahkan. Biasanya akan menggunakan algoritma iteratif yang setiap kali akan memeriksa apakah daya dapat dibagi dua, dan membagi daya dengan dua (dan jika non-habis, gandakan hasilnya denganx
). Ini berarti bahwa untuk12
, itu akan melakukan total enam perkalian. Jika perkalian memiliki kesalahan pembulatan tertentu, kesalahan itu bisa "meledak". Seperti yang dapat kita lihat dalam kode sumber ,(^)
fungsi diimplementasikan sebagai :The
(**)
fungsi, setidaknya untukFloat
s danDouble
s dilaksanakan untuk bekerja pada unit floating point. Memang, jika kita melihat implementasi(**)
, kita melihat:Ini dengan demikian mengarahkan ke
powerFloat# :: Float# -> Float# -> Float#
fungsi, yang biasanya, akan dihubungkan ke operasi FPU yang sesuai oleh kompiler.Jika kita menggunakan
(**)
sebagai gantinya, kita memperoleh nol juga untuk unit floating point 64-bit:Sebagai contoh, kita dapat mengimplementasikan algoritma iteratif dengan Python:
Jika kami kemudian melakukan operasi yang sama, saya mendapatkan secara lokal:
Nilai yang sama dengan yang kami dapatkan
(^)
di GHCi.sumber
pow(..)
fungsi di Python hanya memiliki algoritma tertentu untuk "int / long", bukan untuk mengapung. Untuk pelampung, itu akan "mundur" pada kekuatan FPU.pow()
fungsi.