왜 GHCi가 아래에 잘못된 답변을합니까?
GHCi
λ> ((-20.24373193905347)^12)^2 - ((-20.24373193905347)^24)
4.503599627370496e15
파이썬 3
>>> ((-20.24373193905347)**12)**2 - ((-20.24373193905347)**24)
0.0
업데이트
Haskell의 (^) 기능을 다음과 같이 구현합니다.
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
내 버전이 @WillemVanOnsem에서 제공 한 것보다 더 정확하지는 않지만 적어도이 특정 사례에 대한 정답을 이상하게 제시합니다.
파이썬은 비슷합니다.
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))
답변
짧은 대답 : (^) :: (Num a, Integral b) => a -> b -> a
와 사이에 차이가 (**) :: Floating a => a -> a -> a
있습니다.
이 (^)
함수는 정수 지수에서만 작동합니다. 일반적으로 매번 거듭 제곱이 2로 나눌 수 있는지 확인하고 거듭 제곱을 2로 나눕니다 (분할 할 수없는 경우 결과에 x
)를 곱하는 반복 알고리즘을 사용 합니다. 따라서에 12
대해 총 6 개의 곱셈을 수행합니다 . 곱셈에 반올림 오류가있는 경우 해당 오류는 “폭발”할 수 있습니다. 우리는에서 볼 수 있듯이 소스 코드 의 (^)
함수는 다음과 같이 구현됩니다 :
(^) :: (Num a, Integral b) => a -> b -> a x0 ^ y0 | y0 < 0 = errorWithoutStackTrace "Negative exponent" | y0 == 0 = 1 | otherwise = f x0 y0 where -- f : x0 ^ y0 = x ^ y f x y | even y = f (x * x) (y `quot` 2) | y == 1 = x | otherwise = g (x * x) (y `quot` 2) x -- See Note [Half of y - 1] -- g : x0 ^ y0 = (x ^ y) * z g x y z | even y = g (x * x) (y `quot` 2) z | y == 1 = x * z | otherwise = g (x * x) (y `quot` 2) (x * z) -- See Note [Half of y - 1]
이 (**)
함수는 적어도 Float
s 및 Double
s가 부동 소수점 유닛에서 작동하도록 구현되었습니다. 실제로의 구현을 살펴보면 다음을 (**)
볼 수 있습니다.
instance Floating Float where -- … (**) x y = powerFloat x y -- …
따라서 이것은 powerFloat# :: Float# -> Float# -> Float#
함수로 되며, 일반적으로 컴파일러가 해당 FPU 작업에 연결합니다.
(**)
대신에 사용 하면 64 비트 부동 소수점 단위에 대해서도 0을 얻습니다.
Prelude> (a**12)**2 - a**24
0.0
예를 들어 파이썬에서 반복 알고리즘을 구현할 수 있습니다.
def pw(x0, y0):
if y0 < 0:
raise Error()
if y0 == 0:
return 1
return f(x0, y0)
def f(x, y):
if (y % 2 == 0):
return f(x*x, y//2)
if y == 1:
return x
return g(x*x, y // 2, x)
def g(x, y, z):
if (y % 2 == 0):
return g(x*x, y//2, z)
if y == 1:
return x*z
return g(x*x, y//2, x*z)
그런 다음 동일한 작업을 수행하면 로컬로 가져옵니다.
>>> pw(pw(-20.24373193905347, 12), 2) - pw(-20.24373193905347, 24)
4503599627370496.0
우리가 (^)
GHCi에서 얻는 것과 같은 가치 입니다.