missing pow function?
ryanhart2 opened this issue · comments
Hi,
Is there a particular reason there is no pow function similar to math.pow for Decimals?
Without this, how would you calculate x^y
if x
is a decimal and y
is an integer?
decimal ^ integer
is fairly easy, decimal ^ decimal
is the tricky one and the reason we don't provide the function.
For positive integers in the exponent the algorithm would be:
Enum.reduce(1..exponent, 1, fn _, result ->
Decimal.mult(base, result)
end)
Handling 0 and negative exponents would be fairly easy to add.
Thanks for your response! My internet searching led me to implement as below. It's a bit faster than using the Enum.reduce
method, although possibly not meaningfully so in my app. The implementation below only handles integer exponents, which is okay for my use case but, I guess, not what people would be expecting from an official implementation in the Decimal library.
use Bitwise
alias Decimal
@one Decimal.new(1)
def pow(%Decimal{} = num, exp) when is_integer(exp) and exp > 1 do
pow(@one, num, exp)
end
def pow(%Decimal{} = num, exp) when is_integer(exp) and exp < 0 do
Decimal.div(@one, pow(@one, num, -exp))
end
def pow(%Decimal{} = _num, 0), do: @one
def pow(%Decimal{} = num, 1), do: num
defp pow(result, num, exp) when exp < 2 do
Decimal.mult(result, num)
end
defp pow(result, num, exp) when (exp &&& 1) == 0 do
pow(result, Decimal.mult(num, num), exp >>> 1)
end
defp pow(result, num, exp) when (exp &&& 1) == 1 do
pow(Decimal.mult(result, num), Decimal.mult(num, num), exp >>> 1)
end
The implementation below only handles integer exponents, which is okay for my use case but, I guess, not what people would be expecting from an official implementation in the Decimal library.
Great that you already found a solution. What people would expect is an implementation of decimal ^ decimal
and we don't have an algorithm for that. Contributions or proposals are appreciated.