ich den Code der Umsetzung von (^) der Standard Haskell Bibliothek zu lesen:Umsetzung von (^)
(^) :: (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)
Nun ist dieser Teil, wo g definiert ist, scheint mich seltsam, warum es nicht einfach umzusetzen wie dies:
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)
Aber in der Tat aufstecken sagen 3^1000000 zeigt, dass (^) etwa 0,04 Sekunden schneller als expo ist.
Warum ist
(^)
schneller alsexpo
?
Es ist sicherlich nicht ein sehr dramatisches Problem, aber ich nehme an, was an Ihrer Version ineffizient ist, ist, dass es ziemlich viele Multiplikationen der kleinen Zahl "x" mit einem bereits großen Ergebnis von "f" macht. Die Standardversion erzeugt einen ausgewogeneren Multiplikationsbaum, indem die Restfaktoren den Rekursionsaufruf vollständig durchlaufen. – leftaroundabout
'g' ist tail rekursiv, während das letzte' f' nicht ist. Ich schätze, das ist hier wichtig. – chi