Я читал код реализации (^) из стандартной библиотеки Haskell:Реализация (^)
(^) :: (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 - 1) `quot` 2) x
-- 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 - 1) `quot` 2) (x * z)
Теперь эта часть, где определяется г, кажется странным, почему не просто реализовать, как это:
expo :: (Num a ,Integral b) => a -> b ->a
expo x0 y0
| y0 == 0 = 1
| y0 < 0 = errorWithoutStackTrace "Negative exponent"
| otherwise = f x0 y0
where
f x y | even y = f (x*x) (y `quot` 2)
| y==1 = x
| otherwise = x * f x (y-1)
Но на самом деле подключения сказать 3^+1000000 показывает, что (^) составляет около 0,04 секунды быстрее, чем экспо.
Почему именно
(^)
быстрееexpo
?
Это, конечно, не очень драматичная проблема, но я полагаю, что неэффективна ваша версия, так это то, что она довольно много умножает небольшое число 'x' с уже большим результатом' f'. Стандартная версия генерирует более сбалансированное дерево умножения, посылая остаточные факторы до конца рекурсивного вызова. – leftaroundabout
'g' хвост рекурсивный, а последний' f' - нет. Думаю, это имеет значение. – chi