# `Feel.Runtime.Number.Power`
[🔗](https://github.com/FeeJai/BDM/blob/feel-v0.1.0/apps/feel/lib/feel/runtime/number/power.ex#L1)

The power `base ** exponent` of two FEEL numbers, as one correctly rounded result
(DMN 1.6, decision D-62).

A power is not a repeated multiplication with a rounding at each step: the example
of the specification (the payment `PMT`, section 10.6) comes out right only if the
exact power is rounded once, to 34 digits, half to even. `Feel.Runtime.Number.power/2`
checks the operands and calls `power/2` here, which assumes they are numbers.

**An integer exponent** (its value is, so `2`, `2.0` and `1E+1` are; it may be
negative) takes the exact power of the base and rounds that. The scale follows from
the exactness, as it does for a product: `5 ** 2` is `25`, `5.5 ** 2` is `30.25`,
`5.50 ** 2` is `30.2500`, `10 ** 5` is `100000`. A negative exponent divides one by
the exact power with the scale rule of `Feel.Runtime.Number.divide/2`: the exact
quotient when it has at most 34 digits, otherwise the quotient rounded, so `5 ** -2`
is `0.04` and `10 ** -5` is `0.00001`. A negative base has the sign of the parity
of the exponent.

**Any other exponent** is `exp(y * ln x)`, which has a real value only for a positive
base, so a negative base is `{:error, :out_of_domain}`. It is computed in integer
arithmetic with fixed-point numbers of more than 130 decimal digits, which is far
more than the 34 digits of the result, and the result is rounded from that. The
working precision is raised, until the rounding is certain, if the digits after the
34th are too near to a tie for the error of the computation to decide. The value is
irrational unless the root is exact, so the coefficient of an exact result such as
`4 ** 0.5` has its trailing zeros removed down to the scale of an integer: `2`, `1.5`
for `2.25 ** 0.5`, and `10` for `100 ** 0.5`.

**The special cases.** Any base to the power zero is `1`, zero included. Zero to a
positive power is zero, with the scale of the product for an integer exponent (`0.0 ** 2`
is `0.00`), and zero to a negative power is `{:error, :division_by_zero}`. One to a
fractional power is `1`.

**The range.** A result outside the format is `{:error, :overflow}`, as for the
other operations, and so is a nonzero result too small to write (D-59): `10 ** 6145`,
`0.1 ** 6177`. A power of ten is worked out from its exponent alone, the other
results by an exact integer power while that has at most 10,000 digits and by
logarithms beyond, so that no exponent makes the call slow or large:
`7 ** 99999999999`, `1E+6000 ** 1000000` and `1.000 ** 1000000000` return at once.

There is no process state and no `Decimal` context, and the floating point numbers
that appear are only the estimate of a size, never a digit of a result.

    iex> {:ok, power} = Feel.Runtime.Number.power(Decimal.new("5.5"), Decimal.new(2))
    iex> Decimal.to_string(power, :normal)
    "30.25"
    iex> {:ok, power} = Feel.Runtime.Number.power(Decimal.new(10), Decimal.new(-5))
    iex> Decimal.to_string(power, :normal)
    "0.00001"
    iex> {:ok, power} = Feel.Runtime.Number.power(Decimal.new(2), Decimal.new("0.5"))
    iex> Decimal.to_string(power, :normal)
    "1.414213562373095048801688724209698"
    iex> {:ok, power} = Feel.Runtime.Number.power(Decimal.new("2.25"), Decimal.new("0.5"))
    iex> Decimal.to_string(power, :normal)
    "1.5"
    iex> Feel.Runtime.Number.power(Decimal.new(-4), Decimal.new("0.5"))
    {:error, :out_of_domain}
    iex> Feel.Runtime.Number.power(Decimal.new(10), Decimal.new(6145))
    {:error, :overflow}

# `exp`

```elixir
@spec exp(Decimal.t()) :: Feel.Runtime.Number.result()
```

`e` raised to a number, rounded to 34 digits, half to even.

A result outside the format is `{:error, :overflow}`, as for the other operations, and so is one
too small to write.

    iex> {:ok, e} = Feel.Runtime.Number.Power.exp(Decimal.new(1))
    iex> Decimal.to_string(e, :normal)
    "2.718281828459045235360287471352662"
    iex> {:ok, e} = Feel.Runtime.Number.Power.exp(Decimal.new(5))
    iex> Decimal.to_string(e, :normal)
    "148.4131591025766034211155800405523"
    iex> {:ok, one} = Feel.Runtime.Number.Power.exp(Decimal.new("0.0"))
    iex> Decimal.to_string(one, :normal)
    "1"
    iex> Feel.Runtime.Number.Power.exp(Decimal.new(100000))
    {:error, :overflow}

# `ln`

```elixir
@spec ln(Decimal.t()) :: Feel.Runtime.Number.result()
```

The natural logarithm of a positive number, rounded to 34 digits, half to even.

Zero and the negative numbers have no logarithm: `{:error, :out_of_domain}`.

    iex> {:ok, log} = Feel.Runtime.Number.Power.ln(Decimal.new(10))
    iex> Decimal.to_string(log, :normal)
    "2.302585092994045684017991454684364"
    iex> {:ok, log} = Feel.Runtime.Number.Power.ln(Decimal.new("1.000"))
    iex> Decimal.to_string(log, :normal)
    "0"
    iex> Feel.Runtime.Number.Power.ln(Decimal.new(0))
    {:error, :out_of_domain}

# `power`

```elixir
@spec power(Decimal.t(), Decimal.t()) :: Feel.Runtime.Number.result()
```

Raises `base` to `exponent`. Both must be FEEL numbers.

    iex> {:ok, power} = Feel.Runtime.Number.Power.power(Decimal.new(5), Decimal.new(-2))
    iex> Decimal.to_string(power, :normal)
    "0.04"

---

*Consult [api-reference.md](api-reference.md) for complete listing*
