# `Cldr.Math`
[🔗](https://github.com/elixir-cldr/cldr_utils/blob/v2.29.5/lib/cldr/utils/math.ex#L1)

Math helper functions for number formatting.

# `normalised_decimal`

```elixir
@type normalised_decimal() ::
  {%Decimal{coef: term(), exp: term(), sign: term()}, integer()}
```

# `number_or_decimal`

```elixir
@type number_or_decimal() ::
  number() | %Decimal{coef: term(), exp: term(), sign: term()}
```

# `rounding`

```elixir
@type rounding() ::
  :down | :half_up | :half_even | :ceiling | :floor | :half_down | :up
```

# `add`
*since 2.25.0* 

Adds two numbers together.

The numbers can be integers, floats or Decimals.
The type of the return will be Decimal if the
either of the arguments is a Decimal.

If both arguments are integers, the result will
be an integer. If either of the arguments is a float,
the result will be a float.

# `amod`

```elixir
@spec amod(number_or_decimal(), number_or_decimal()) :: number_or_decimal()
```

Returns the adjusted modulus of `x` and `y`.

# `approximation_error`

Calculates the error between the original float and the rational approximation.

### Arguments

* `float` is the original float

* `{numerator, denominator}` is the approximate ratio for the float

# `coef_exponent`

```elixir
@spec coef_exponent(number_or_decimal()) :: {number_or_decimal(), integer()}
```

Returns a tuple representing a number in a normalized form with
the mantissa in the range `0 < m < 10` and a base 10 exponent.

* `number` is an integer, float or Decimal

## Examples

    Cldr.Math.coef_exponent(Decimal.new(1.23004))
    {Decimal.new("1.23004"), 0}

    Cldr.Math.coef_exponent(Decimal.new(465))
    {Decimal.new("4.65"), 2}

    Cldr.Math.coef_exponent(Decimal.new(-46.543))
    {Decimal.new("-4.6543"), 1}

# `coef_exponent_digits`

```elixir
@spec coef_exponent_digits(number_or_decimal()) :: {Cldr.Digits.t(), integer()}
```

Returns a tuple representing a number in a normalized form with
the mantissa in the range `0 < m < 10` and a base 10 exponent.

The mantissa is represented as tuple of the form `Digits.t`.

* `number` is an integer, float or Decimal

## Examples

    Cldr.Math.coef_exponent_digits(Decimal.new(1.23004))
    {{[1, 2, 3, 0], 1, 1}, 0}

    Cldr.Math.coef_exponent_digits(Decimal.new(465))
    {{[4, 6, 5], 1, 1}, -1}

    Cldr.Math.coef_exponent_digits(Decimal.new(-46.543))
    {{[4, 6, 5, 4], 1, -1}, 1}

# `convergents`

# `default_rounding`

```elixir
@spec default_rounding() :: integer()
```

Returns the default number of rounding digits.

# `default_rounding_mode`

```elixir
@spec default_rounding_mode() :: atom()
```

Returns the default rounding mode for rounding operations.

# `div`
*since 2.25.0* 

Divides one number by the other.

The numbers can be integers, floats or Decimals.
The type of the return will be Decimal if the
either of the arguments is a Decimal.

If both arguments are numbers, the resulting type
will be a be a Decimal.

# `div_amod`

```elixir
@spec div_amod(integer(), integer()) :: {integer(), integer()}
```

Returns the adjusted remainder and dividend of two
integers.

This version will return the divisor if the remainder
would otherwise be zero.

# `div_mod`

```elixir
@spec div_mod(integer(), integer()) :: {integer(), integer()}
```

Returns the remainder and dividend of two integers.

# `float_to_ratio`

Converts a float to a rational number {numerator, denominator}.

Note this code is adapted from that generated by Claude.ai. There
is definitely room for improvement and optimisation.

### Arguments

* `x` is any float.

* `options` is a keyword list of options.

### Options

- `:max_iterations` - Maximum number of continued fraction terms (default: 20)

- `:epsilon` - Tolerance for float comparisons (default: 1.0e-10)

- `:max_denominator` - Maximum allowed denominator (default: nil meaning no limited)

##$ Examples

    iex> Cldr.Math.float_to_ratio(0.75)
    {3, 4}

    iex> Cldr.Math.float_to_ratio(3.14159, max_iterations: 5)
    {9208, 2931}

    iex> Cldr.Math.float_to_ratio(3.14159, max_denominator: 10)
    {22, 7}

    iex> Cldr.Math.float_to_ratio(1.42, max_denominator: 10)
    {10, 7}

# `log10`

```elixir
@spec log10(number_or_decimal()) :: number_or_decimal()
```

Return the log10 of a number.

* `number` is an integer, a float or a Decimal

  * For integer and float it calls the BIF `:math.log10/1` function.

  * For `Decimal`, `log10` is is rolled by hand using the identify `log10(x) =
  ln(x) / ln(10)`

## Examples

    iex> Cldr.Math.log10(100)
    2.0

    iex> Cldr.Math.log10(123)
    2.089905111439398

    iex> Cldr.Math.log10(Decimal.new(9000))
    Decimal.new("3.953767554157656512064441441")

# `log`

Return the natural log of a number.

* `number` is an integer, a float or a Decimal

* For integer and float it calls the BIF `:math.log10/1` function.

* For Decimal the log is rolled by hand.

## Examples

    iex> Cldr.Math.log(123)
    4.812184355372417

    iex> Cldr.Math.log(Decimal.new(9000))
    Decimal.new("9.103886231350952380952380952")

# `maybe_integer`

# `mod`

```elixir
@spec mod(number_or_decimal(), number_or_decimal()) :: number_or_decimal()
```

Calculates the modulo of a number (integer, float or Decimal).

Note that this function uses `floored division` whereas the builtin `rem`
function uses `truncated division`. See `Decimal.rem/2` if you want a
`truncated division` function for Decimals that will return the same value as
the BIF `rem/2` but in Decimal form.

See [Wikipedia](https://en.wikipedia.org/wiki/Modulo_operation) for an
explanation of the difference.

## Examples

    iex> Cldr.Math.mod(1234.0, 5)
    4.0

    iex> Cldr.Math.mod(Decimal.new("1234.456"), 5)
    Decimal.new("4.456")

    iex> Cldr.Math.mod(Decimal.new("123.456"), Decimal.new("3.4"))
    Decimal.new("1.056")

    iex> Cldr.Math.mod Decimal.new("123.456"), 3.4
    Decimal.new("1.056")

# `mult`
*since 2.25.0* 

Multiplies two numbers together.

The numbers can be integers, floats or Decimals.
The type of the return will be Decimal if the
either of the arguments is a Decimal.

If both arguments are integers, the result will
be an integer. If either of the arguments is a float,
the result will be a float.

# `pow`

Raises one number to an exponent.

# `power`

```elixir
@spec power(number_or_decimal(), number_or_decimal()) :: number_or_decimal()
```

Raises a number to a integer power.

Raises a number to a power using the the binary method. There is one
exception for Decimal numbers that raise `10` to some power. In this case the
power is calculated by shifting the Decimal exponent which is quite efficient.

For further reading see
[this article](http://videlalvaro.github.io/2014/03/the-power-algorithm.html)

> This function works only with integer exponents!

## Examples

    iex> Cldr.Math.power(10, 2)
    100

    iex> Cldr.Math.power(10, 3)
    1000

    iex> Cldr.Math.power(10, 4)
    10000

    iex> Cldr.Math.power(2, 10)
    1024

# `root`

Calculate the nth root of a number.

* `number` is an integer or a Decimal

* `nth` is a positive integer

## Examples

    iex> Cldr.Math.root Decimal.new(8), 3
    Decimal.new("2.0")

    iex> Cldr.Math.root Decimal.new(16), 4
    Decimal.new("2.0")

    iex> Cldr.Math.root Decimal.new(27), 3
    Decimal.new("3.0")

# `round`

Round a number to an arbitrary precision using one of several rounding algorithms.

Rounding algorithms are based on the definitions given in IEEE 754, but also
include 2 additional options (effectively the complementary versions):

## Arguments

* `number` is a `float`, `integer` or `Decimal`

* `places` is an integer number of places to round to

* `mode` is the rounding mode to be applied.  The
  default is `:half_even`

## Rounding algorithms

Directed roundings:

* `:down` - Round towards 0 (truncate), eg 10.9 rounds to 10.0

* `:up` - Round away from 0, eg 10.1 rounds to 11.0. (Non IEEE algorithm)

* `:ceiling` - Round toward +∞ - Also known as rounding up or ceiling

* `:floor` - Round toward -∞ - Also known as rounding down or floor

Round to nearest:

* `:half_even` - Round to nearest value, but in a tiebreak, round towards the
  nearest value with an even (zero) least significant bit, which occurs 50%
  of the time. This is the default for IEEE binary floating-point and the recommended
  value for decimal.

* `:half_up` - Round to nearest value, but in a tiebreak, round away from 0.
  This is the default algorithm for Erlang's Kernel.round/2

* `:half_down` - Round to nearest value, but in a tiebreak, round towards 0
  (Non IEEE algorithm)

## Notes

* When the `number` is a `Decimal`, the results are identical
  to `Decimal.round/3` (delegates to `Decimal` in these cases)

* When the `number` is a `float`, `places` is `0` and `mode`
  is `:half_up` then the result is the same as `Kernel.trunc/1`

* The results of rounding for `floats` may not return the same
  result as `Float.round/2`. `Float.round/2` operates on the
  binary representation. This implementation operates on
  a decimal representation.

# `round_significant`

```elixir
@spec round_significant(number_or_decimal(), integer()) :: number_or_decimal()
```

Rounds a number to a specified number of significant digits.

This is not the same as rounding fractional digits which is performed
by `Decimal.round/2` and `Float.round`

* `number` is a float, integer or Decimal

* `n` is the number of significant digits to which the `number` should be
  rounded

## Examples

    iex> Cldr.Math.round_significant(3.14159, 3)
    3.14

    iex> Cldr.Math.round_significant(10.3554, 1)
    10.0

    iex> Cldr.Math.round_significant(0.00035, 1)
    0.0004

    iex> Cldr.Math.round_significant(Decimal.from_float(3.342742283480345e27), 7)
    Decimal.new("3.342742E+27")

## Notes about precision

Since floats cannot accurately represent all decimal
numbers, so rounding to significant digits for a float cannot
always return the expected results. For example:

    => Cldr.Math.round_significant(3.342742283480345e27, 7)
    Expected result:  3.342742e27
    Actual result: 3.3427420000000003e27

Use of `Decimal` numbers avoids this issue:

    => Cldr.Math.round_significant(Decimal.from_float(3.342742283480345e27), 7)
    Expected result:  #Decimal<3.342742E+27>
    Actual result: #Decimal<3.342742E+27>

## More on significant digits

* 3.14159 has six significant digits (all the numbers give you useful
  information)

* 1000 has one significant digit (only the 1 is interesting; you don't know
  anything for sure about the hundreds, tens, or units places; the zeroes may
  just be placeholders; they may have rounded something off to get this value)

* 1000.0 has five significant digits (the ".0" tells us something interesting
  about the presumed accuracy of the measurement being made: that the
  measurement is accurate to the tenths place, but that there happen to be
  zero tenths)

* 0.00035 has two significant digits (only the 3 and 5 tell us something; the
  other zeroes are placeholders, only providing information about relative
  size)

* 0.000350 has three significant digits (that last zero tells us that the
  measurement was made accurate to that last digit, which just happened to
  have a value of zero)

* 1006 has four significant digits (the 1 and 6 are interesting, and we have
  to count the zeroes, because they're between the two interesting numbers)

* 560 has two significant digits (the last zero is just a placeholder)

* 560.0 has four significant digits (the zero in the tenths place means that
  the measurement was made accurate to the tenths place, and that there just
  happen to be zero tenths; the 5 and 6 give useful information, and the
  other zero is between significant digits, and must therefore also be
  counted)

Many thanks to [Stackoverflow](http://stackoverflow.com/questions/202302/rounding-to-an-arbitrary-number-of-significant-digits)

# `sqrt`

Calculates the square root of a Decimal number using Newton's method.

* `number` is an integer, float or Decimal.  For integer and float,
`sqrt` is delegated to the erlang `:math` module.

We convert the Decimal to a float and take its
`:math.sqrt` only to get an initial estimate.
The means typically we are only two iterations from
a solution so the slight hack improves performance
without sacrificing precision.

## Examples

    iex> Cldr.Math.sqrt(Decimal.new(9))
    Decimal.new("3.0")

    iex> Cldr.Math.sqrt(Decimal.new("9.869"))
    Decimal.new("3.141496458696078173887197038")

# `sub`
*since 2.25.0* 

Subtracts one number from another.

The numbers can be integers, floats or Decimals.
The type of the return will be Decimal if the
either of the arguments is a Decimal.

If both arguments are integers, the result will
be an integer. If either of the arguments is a float,
the result will be a float.

# `to_float`

```elixir
@spec to_float(%Decimal{coef: term(), exp: term(), sign: term()}) :: float()
```

Convert a Decimal to a float

* `decimal` must be a Decimal

This is very likely to lose precision - lots of numbers won't
make the round trip conversion.  Use with care.  Actually, better
not to use it at all.

# `within`

```elixir
@spec within(number(), integer() | Range.t()) :: boolean()
```

Check if a `number` is within a `range`.

* `number` is either an integer or a float.

When an integer, the comparison is made using the standard Elixir `in`
operator.

When `number` is a float the comparison is made using the `>=` and `<=`
operators on the range endpoints. Note the comparison for a float is only for
floats that have no fractional part. If a float has a fractional part then
`within` returns `false`.

*Since this function is only provided to support plural rules, the float
comparison is only useful if the float has no fractional part.*

## Examples

    iex> Cldr.Math.within(2.0, 1..3)
    true

    iex> Cldr.Math.within(2.1, 1..3)
    false

---

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