# `Money`
[🔗](https://github.com/kipcole9/money/blob/v6.0.0-rc.0/lib/money.ex#L1)

Money implements a set of functions to store, retrieve, convert and perform
arithmetic on a `t:Money.t/0` type that is composed of a currency code and
a decimal currency amount.

Money is very opinionated in the interests of serving as a dependable library
that can underpin accounting and financial applications.

This opinion expressed by ensuring that:

1. Money must always have both a amount and a currency code.

2. The currency code must always be valid.

3. Money arithmetic can only be performed when both operands are of the
   same currency.

4. Money amounts are represented as a `Decimal`.

5. Money is serialised to the database as a custom Postgres composite type
   that includes both the amount and the currency. Therefore for Ecto
   serialization Postgres is assumed as the data store. Serialization is
   entirely optional and Ecto is not a package dependency.

6. All arithmetic functions work in fixed point decimal.  No rounding
   occurs automatically (unless expressly called out for a function).

7. Explicit rounding obeys the rounding rules for a given currency.  The
   rounding rules are defined by the Unicode consortium in its CLDR
   repository as implemented by the hex package `localize`.  These rules
   define the number of fractional digits for a currency and the rounding
   increment where appropriate.

# `amount`

```elixir
@type amount() :: float() | integer() | Decimal.t() | String.t()
```

An amount can be expressed as a float, an integer,
a Decimal or a string (which is converted to a Decimal)

# `currency_reference`

```elixir
@type currency_reference() :: atom() | String.t()
```

A value that can reference a currency. This is either:

* An atom — an ISO 4217 currency code (e.g. `:USD`) or a custom/private-use
  currency code registered via `Money.Currency.new/2` (e.g. `:XBT`).

* A binary — either a string form of an ISO code (e.g. `"USD"`), a digital
  token short name (e.g. `"BTC"`), or a 9-character ISO 24165 digital
  token identifier (DTI).

# `t`

```elixir
@type t() :: %Money{
  amount: Decimal.t(),
  currency: currency_reference(),
  format_options: Keyword.t()
}
```

Money is composed of an atom representation of an ISO4217 currency code or a custom
currency code and a `Decimal` representation of an amount.

# `abs`

```elixir
@spec abs(money :: t()) :: t()
```

The absolute value of a `t:Money.t/0` amount.
Returns a `t:Money.t/0` type with a positive sign for the amount.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

### Returns

* a `t:Money.t/0`.

## Example

    iex> m = Money.new("USD", -100)
    iex> Money.abs(m)
    Money.new(:USD, "100")

# `add`

```elixir
@spec add(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Add two `Money` values.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

* `{:ok, money}` or

* `{:error, reason}`.

## Example

    iex> Money.add Money.new(:USD, 200), Money.new(:USD, 100)
    {:ok, Money.new(:USD, 300)}

    iex> Money.add Money.new(:USD, 200), Money.new(:AUD, 100)
    {:error, {ArgumentError, "Cannot add monies with different currencies. " <>
      "Received :USD and :AUD."}}

# `add!`

```elixir
@spec add!(money_1 :: t(), money_2 :: t()) :: t() | no_return()
```

Add two `t:Money.t/0` values or raise on error.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

* a `t:Money.t/0` struct or

* raises an exception

### Examples

    iex> Money.add! Money.new(:USD, 200), Money.new(:USD, 100)
    Money.new(:USD, "300")

    Money.add! Money.new(:USD, 200), Money.new(:CAD, 500)
    ** (ArgumentError) Cannot add two %Money{} with different currencies. Received :USD and :CAD.

# `clamp`
*since 5.18.0* 

```elixir
@spec clamp(money :: t(), minimum :: t(), maximum :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Clamps a `t:Money.t/0` to be in the range of `minimum`
to `maximum`.

#### Arguments

* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. They should be of the same currency.

#### Returns

* `{:ok, money]` where `money` is clamped to the `minimum` or `maximum` if required.
    * If `money` is within the range `minimum..maximum` then `money` is returned unchanged.
    * If `money` is less than `minimum` then `minimum` is returned.
    * If `money` is greater than `maximum` then `maximum` is returned.

* or `{:error, reason}`.

#### Examples

    iex> Money.clamp(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
    {:ok, Money.new(:USD, 100)}

    iex> Money.clamp(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
    {:ok, Money.new(:USD, 200)}

    iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
    {:ok, Money.new(:USD, 50)}

    iex> Money.clamp(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
    {:error,
      {ArgumentError,
        "Minimum must be less than maximum. Found Money.new(:USD, \"300\") and Money.new(:USD, \"200\")"}}

    iex> Money.clamp(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
    {:error, {ArgumentError, "Cannot compare monies with different currencies. Received :USD, :AUD and :EUR"}}

# `clamp!`
*since 5.18.0* 

```elixir
@spec clamp!(money :: t(), minimum :: t(), maximum :: t()) :: t() | no_return()
```

Clamps a `t:Money.t/0` to be in the range of `minimum`
to `maximum` or raises an exception.

#### Arguments

* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. They should be of the same currency.

#### Returns

* `money` where `money` is clamped to the `minimum` or `maximum` if required.
    * If `money` is within the range `minimum..maximum` then `money` is returned unchanged.
    * If `money` is less than `minimum` then `minimum` is returned.
    * If `money` is greater than `maximum` then `maximum` is returned.

* or `{:error, reason}`.

#### Examples

    iex> Money.clamp!(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
    Money.new(:USD, 100)

    iex> Money.clamp!(Money.new(:USD, 300), Money.new(:USD, 50), Money.new(:USD, 200))
    Money.new(:USD, 200)

    iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
    Money.new(:USD, 50)

    iex> Money.clamp!(Money.new(:USD, 10), Money.new(:USD, 300), Money.new(:USD, 200))
    ** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")

    iex> Money.clamp!(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR

# `cmp`

```elixir
@spec cmp(money_1 :: t(), money_2 :: t()) ::
  -1 | 0 | 1 | {:error, {module(), String.t()}}
```

Compares two `Money` values numerically. If the first number is greater
than the second #Integer<1> is returned, if less than Integer<-1> is
returned. Otherwise, if both numbers are equal Integer<0> is returned.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

*  `-1` | `0` | `1` or

* `{:error, {module(), String.t}}`

### Examples

    iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 100)
    1

    iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 200)
    0

    iex> Money.cmp Money.new(:USD, 200), Money.new(:USD, 500)
    -1

    iex> Money.cmp Money.new(:USD, 200), Money.new(:CAD, 500)
    {:error,
     {ArgumentError,
      "Cannot compare monies with different currencies. Received :USD and :CAD."}}

# `cmp!`

Compares two `Money` values numerically and raises on error.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`

### Returns

*  `-1` | `0` | `1` or

* raises an exception

### Examples

    Money.cmp! Money.new(:USD, 200), Money.new(:CAD, 500)
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.

# `compare`

```elixir
@spec compare(money_1 :: t(), money_2 :: t()) ::
  :gt | :eq | :lt | {:error, {module(), String.t()}}
```

Compares two `Money` values numerically. If the first number is greater
than the second :gt is returned, if less than :lt is returned, if both
numbers are equal :eq is returned.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`

### Returns

*  `:gt` | `:eq` | `:lt` or

* `{:error, {module(), String.t}}`

### Examples

    iex> Money.compare(Money.new(:USD, 200), Money.new(:USD, 100))
    :gt

    iex> Money.compare(Money.new(:USD, 200), Money.new(:USD, 200))
    :eq

    iex> Money.compare(Money.new(:USD, 200), Money.new(:USD, 500))
    :lt

    iex> Money.compare(Money.new(:USD, 200), Money.new(:CAD, 500))
    {:error,
     {ArgumentError,
      "Cannot compare monies with different currencies. Received :USD and :CAD."}}

# `compare!`

Compares two `Money` values numerically and raises on error.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

*  `:gt` | `:eq` | `:lt` or

* raises an exception

### Examples

    Money.compare! Money.new(:USD, 200), Money.new(:CAD, 500)
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :CAD.

# `cross_rate`

```elixir
@spec cross_rate(
  t() | currency_reference(),
  currency_reference(),
  Money.ExchangeRates.t() | {:ok, Money.ExchangeRates.t()}
) :: {:ok, Decimal.t()} | {:error, {module(), String.t()}}
```

Returns the effective cross-rate to convert from one currency
to another.

### Arguments

* `from` is any `t:Money.t/0` struct returned by `Money.Currency.new/2` or a valid
   currency code.

* `to_currency` is a valid currency code into which the `money` is converted.

* `rates` is a `Map` of currency rates where the map key is an upcased
  atom or string and the value is a Decimal conversion factor.  The default is the
  latest available exchange rates returned from `Money.ExchangeRates.latest_rates/0`.

### Examples

    Money.cross_rate(Money.new(:USD, 100), :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
    {:ok, Decimal.new("0.7345")}

    Money.cross_rate Money.new(:USD, 100), :ZZZ, %{USD: Decimal.new(1), AUD: Decimal.new(0.7345)}
    ** (Money.UnknownCurrencyError) The currency :ZZZ is not known.

# `cross_rate!`

```elixir
@spec cross_rate!(
  t() | currency_reference(),
  currency_reference(),
  Money.ExchangeRates.t() | {:ok, Money.ExchangeRates.t()}
) :: Decimal.t() | no_return()
```

Returns the effective cross-rate to convert from one currency
to another.

### Arguments

* `from` is any `t:Money.t/0` struct returned by `Money.Currency.new/2` or a valid
   currency code.

* `to_currency` is a valid currency code into which the `money` is converted.

* `rates` is a `Map` of currency rates where the map key is an upcased
  atom or string and the value is a Decimal conversion factor.  The default is the
  latest available exchange rates returned from `Money.ExchangeRates.latest_rates/0`.

### Examples

    iex> Money.cross_rate!(Money.new(:USD, 100), :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
    Decimal.new("0.7345")

    iex> Money.cross_rate!(:USD, :AUD, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")})
    Decimal.new("0.7345")

    Money.cross_rate Money.new(:USD, 100), :ZZZ, %{USD: Decimal.new(1), AUD: Decimal.new("0.7345")}
    ** (Money.UnknownCurrencyError) The currency :ZZZ is not known.

# `default_rounding_mode`
*since 5.18.1* 

Returns the default rounding mode.

# `div`

```elixir
@spec div(t(), Localize.Utils.Math.number_or_decimal()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Divide a `Money` value by a number.

### Arguments

* `money` is any valid `t:Money.t/0` types returned
  by `Money.new/2`

* `number` is an integer, float or `Decimal.t`

> Note that dividing one %Money{} by another is not supported.

### Returns

* `{:ok, money}` or

* `{:error, reason}`

## Example

    iex> Money.div Money.new(:USD, 200), 2
    {:ok, Money.new(:USD, 100)}

    iex> Money.div(Money.new(:USD, 200), "xx")
    {:error, {ArgumentError, "Cannot divide money by \"xx\""}}

# `div!`

```elixir
@spec div!(t(), Localize.Utils.Math.number_or_decimal()) :: t() | none()
```

Divide a `Money` value by a number and raise on error.

### Arguments

* `money` is any valid `t:Money.t/0` types returned
  by `Money.new/2`

* `number` is an integer, float or `Decimal.t`

### Returns

* a `t:Money.t/0` struct or

* raises an exception

### Examples

    iex> Money.div!(Money.new(:USD, 200), 2)
    Money.new(:USD, "100")

    iex> Money.div!(Money.new(:USD, 200), "xx")
    ** (ArgumentError) Cannot divide money by "xx"

# `equal?`

```elixir
@spec equal?(money_1 :: t(), money_2 :: t()) :: boolean()
```

Returns a boolean indicating if two `Money` values are equal

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`

### Returns

* `true` or `false`

## Example

    iex> Money.equal?(Money.new(:USD, 200), Money.new(:USD, 200))
    true

    iex> Money.equal?(Money.new(:USD, 200), Money.new(:USD, 100))
    false

# `from_float`
*since 2.0.0* 

```elixir
@spec from_float(
  float() | currency_reference(),
  float() | currency_reference(),
  Keyword.t()
) :: t() | {:error, {module(), String.t()}}
```

Returns a `t:Money.t/0` from a currency code and a float amount, or
an error tuple of the form `{:error, {exception, message}}`.

Floats are fraught with danger in computer arithmetic due to the
unexpected loss of precision during rounding. The IEEE754 standard
indicates that a number with a precision of 16 digits should
round-trip convert without loss of fidelity. This function supports
numbers with a precision up to 15 digits and will error if the
provided amount is outside that range.

**Note** that `Money` cannot detect lack of precision or rounding errors
introduced upstream. This function therefore should be used with
great care and its use should be considered potentially harmful.

### Arguments

* `currency_code` is an [ISO4217](https://en.wikipedia.org/wiki/ISO_4217)
  binary or atom currency code or an
  [ISO 24165](https://www.iso.org/standard/80601.html) token identifier or shortname.

* `amount` is a float

* `options` is a keyword list of options passed
  to `Money.new/3`. The default is `[]`.

### Examples

    iex> Money.from_float 1.23456, :USD
    Money.new(:USD, "1.23456")

    iex> Money.from_float 1.234567890987656, :USD
    {:error,
      {Money.InvalidAmountError,
        "The precision of the float 1.234567890987656 is " <>
        "greater than 15 which could lead to unexpected results. " <>
        "Reduce the precision or call Money.new/2 with a Decimal or String amount"}}

# `from_float!`
*since 2.0.0* 

```elixir
@spec from_float!(currency_reference(), float(), Keyword.t()) :: t() | no_return()
```

Returns a `t:Money.t/0` from a currency code and a float amount, or
raises an exception if the currency code is invalid.

See `Money.from_float/2` for further information.

**Note** that `Money` cannot detect lack of precision or rounding errors
introduced upstream. This function therefore should be used with
great care and its use should be considered potentially harmful.

### Arguments

* `currency_code` is an [ISO4217](https://en.wikipedia.org/wiki/ISO_4217)
  binary or atom currency code or an
  [ISO 24165](https://www.iso.org/standard/80601.html) token identifier or shortname.

* `amount` is a float.

* `options` is a keyword list of options passed
  to `Money.new/3`. The default is `[]`.

### Examples

    iex> Money.from_float!(:USD, 1.234)
    Money.new(:USD, "1.234")

    Money.from_float!(:USD, 1.234567890987654)
    #=> ** (Money.InvalidAmountError) The precision of the float 1.234567890987654 is greater than 15 which could lead to unexpected results. Reduce the precision or call Money.new/2 with a Decimal or String amount
        (ex_money) lib/money.ex:293: Money.from_float!/2

# `from_integer`

```elixir
@spec from_integer(integer(), currency_reference(), Keyword.t()) ::
  t() | {:error, {module(), String.t()}}
```

Convert an integer representation of money into a `Money` struct.

### Arguments

* `integer` is an integer representation of a money amount including
  any decimal digits.  ie. `20000` would be interpreted to mean `$200.00`
  if the `currency` is `:USD` and no `:currency_digits` option
  was provided.

* `currency` is the currency code for the `integer`.  The assumed
  decimal precision is derived from the currency code if no `fractional_digits`
  option is specified.

* `options` is a keyword list of options.

### Options

* `:currency_digits` which determines the currency precision implied
  by the `integer`. The valid options are `:cash`, `:accounting`,
  `:iso` or a non-negative integer. The default is `:iso` which uses the
  [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217) definition of
  currency digits.

All other options are passed to `Money.new/3`.

### Returns

* A `t:Money.t/0` struct or

* `{:error, {exception, message}}`

### Notes

* Some currencies, like the [Iraqi Dinar](https://en.wikipedia.org/wiki/Iraqi_dinar)
  have a difference in the decimal digits defined by CLDR versus
  those defined by [ISO 4217](https://en.wikipedia.org/wiki/ISO_4217). CLDR
  defines the decimal digits for `IQD` as `0` whereas ISO 4217 defines
  `3` decimal digits.

* Since converting an integer to a money amount is very
  sensitive to the number of fractional digits specified it is
  important to be very clear about the precision of the data used
  with this function and care taken in specifying the `:fractional_digits`
  parameter.

### Examples

    iex> Money.from_integer(20000, :USD)
    Money.new(:USD, "200.00")

    iex> Money.from_integer(200, :JPY)
    Money.new(:JPY, "200")

    iex> Money.from_integer(20012, :USD)
    Money.new(:USD, "200.12")

    iex> Money.from_integer(20012, :USD, currency_digits: 3)
    Money.new(:USD, "20.012")

    iex> Money.from_integer(20012, :IQD)
    Money.new(:IQD, "20.012")

# `get_env`

# `integer?`
*since 5.10.0* 

```elixir
@spec integer?(t()) :: boolean()
```

Returns a boolean indicating if `t:Money.t/0`
is an integer value (has no significant fractional
digits).

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`

### Example

    iex> Money.integer?(Money.new(:USD, 0))
    true

    iex> Money.integer?(Money.new(:USD, "1.10"))
    false

# `known_currencies`

# `known_current_currencies`

# `known_historic_currencies`

# `known_tender_currencies`

# `localize`
*since 5.12.0* 

```elixir
@spec localize(t(), Keyword.t()) :: {:ok, t()} | {:error, {module(), String.t()}}
```

Localizes a `Money` by converting it to the currency
of the specified locale.

### Arguments

* `money` is any `t:Money.t/0` struct returned by `Money.Currency.new/2`.

* `options` is a keyword list of options.

### Options

* `:locale` is any valid locale returned by `Localize.supported_locales/0`
  or a `Localize.LanguageTag` struct.
  The default is `Localize.get_locale/0`.

### Returns

* `{:ok, localized_money}` or

* `{:error, {exception, reason}}`

# `max`
*since 5.18.0* 

```elixir
@spec max(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Return the maximum of two `t:Money.t/0` amounts.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. `money_1` and `money_2` should be of the same
  currency.

### Returns

* `{:ok, maximum_money}` or

* `{:error, reason}`.

## Example

    iex> Money.max(Money.new(:USD, 200), Money.new(:USD, 300))
    {:ok, Money.new(:USD, 300)}

    iex> Money.max(Money.new(:USD, 200), Money.new(:AUD, 200))
    {:error,
      {ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}

# `max!`
*since 5.18.0* 

```elixir
@spec max!(money_1 :: t(), money_2 :: t()) :: t() | no_return()
```

Return the maximum of two `t:Money.t/0` amounts or
raises an exception.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. `money_1` and `money_2` should be of the same
  currency.

### Returns

* `maximum_money` or

* raises an exception.

## Example

    iex> Money.max!(Money.new(:USD, 200), Money.new(:USD, 300))
    Money.new(:USD, 300)

    iex> Money.max!(Money.new(:USD, 200), Money.new(:AUD, 200))
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.

# `min`
*since 5.18.0* 

```elixir
@spec min(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Return the minimum of two `t:Money.t/0` amounts.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. `money_1` and `money_2` should be of the same
  currency.

### Returns

* `{:ok, minimum_money}` or

* `{:error, reason}`

## Example

    iex> Money.min(Money.new(:USD, 200), Money.new(:USD, 300))
    {:ok, Money.new(:USD, 200)}

    iex> Money.min(Money.new(:USD, 200), Money.new(:AUD, 200))
    {:error,
      {ArgumentError, "Cannot compare monies with different currencies. Received :USD and :AUD."}}

# `min!`
*since 5.18.0* 

```elixir
@spec min!(money_1 :: t(), money_2 :: t()) :: t() | no_return()
```

Return the minimum of two `t:Money.t/0` amounts or
raises an exception.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. `money_1` and `money_2` should be of the same
  currency.

### Returns

* `minimum_money` or

* raises an exception.

## Example

    iex> Money.min!(Money.new(:USD, 200), Money.new(:USD, 300))
    Money.new(:USD, 200)

    iex> Money.min!(Money.new(:USD, 200), Money.new(:AUD, 200))
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD and :AUD.

# `mult`

```elixir
@spec mult(t(), Localize.Utils.Math.number_or_decimal()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Multiply a `Money` value by a number.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

* `number` is an integer, float or `t:Decimal.t/0`.

> Note that multipling one `t:Money.t/0` by another is not supported.

### Returns

* `{:ok, money}` or

* `{:error, reason}`

## Example

    iex> Money.mult(Money.new(:USD, 200), 2)
    {:ok, Money.new(:USD, 400)}

    iex> Money.mult(Money.new(:USD, 200), "xx")
    {:error, {ArgumentError, "Cannot multiply money by \"xx\""}}

# `mult!`

```elixir
@spec mult!(t(), Localize.Utils.Math.number_or_decimal()) :: t() | none()
```

Multiply a `Money` value by a number and raise on error.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

* `number` is an integer, float or `t:Decimal.t/0`.

### Returns

* a `t:Money.t/0` or

* raises an exception

### Examples

    iex> Money.mult!(Money.new(:USD, 200), 2)
    Money.new(:USD, "400")

    Money.mult!(Money.new(:USD, 200), :invalid)
    ** (ArgumentError) Cannot multiply money by :invalid

# `negate`
*since 5.18.0* 

```elixir
@spec negate(money :: t()) :: {:ok, t()}
```

Negate a `t:Money.t/0` value.

### Argument

* `money_1` is any valid `t:Money.t/0` type.

#### Returns

* `{:ok, negated_money}` with the amount negated.

### Example

    iex> Money.negate(Money.new(:USD, 200))
    {:ok, Money.new(:USD, -200)}

    iex> Money.negate(Money.new(:USD, -200))
    {:ok, Money.new(:USD, 200)}

# `negate!`
*since 5.18.0* 

```elixir
@spec negate!(money :: t()) :: t() | no_return()
```

Negate a `t:Money.t/0` value or raises an
exception.

### Argument

* `money_1` is any valid `t:Money.t/0` type.

#### Returns

* `negated_money` with the amount negated or

* raises an exception.

### Example

    iex> Money.negate!(Money.new(:USD, 200))
    Money.new(:USD, -200)

    iex> Money.negate!(Money.new(:USD, -200))
    Money.new(:USD, 200)

# `negative?`
*since 5.10.0* 

```elixir
@spec negative?(t()) :: boolean()
```

Returns a boolean indicating if `t:Money.t/0`
has a negative value.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`

### Example

    iex> Money.negative?(Money.new(:USD, -1))
    true

    iex> Money.negative?(Money.new(:USD, 0))
    false

    iex> Money.negative?(Money.new(:USD, 1))
    false

# `new`

```elixir
@spec new(
  amount() | currency_reference(),
  amount() | currency_reference(),
  Keyword.t()
) :: t() | {:error, {module(), String.t()}}
```

Returns a `t:Money.t/0` from a currency code and a currency amount or
an error tuple of the form `{:error, {exception, message}}`.

### Arguments

* `currency_code` is an [ISO4217](https://en.wikipedia.org/wiki/ISO_4217)
  binary or atom currency code or an
  [ISO 24165](https://www.iso.org/standard/80601.html) token identifier or shortname.

* `amount` is an integer, string or Decimal money amount.

* `options` is a keyword list of options.

### Options

* `:locale` is any known locale.  The locale is used to normalize any
  binary (String) amounts to a form that can be consumed by `Decimal.new/1`.
  This consists of removing any localised grouping characters and replacing
  the localised decimal separator with a ".".
  The default is `Localize.get_locale/0`.

* `:separators` selects which of the available symbol
  sets should be used when attempting to parse a string into a number.
  The default is `:standard`. Some limited locales have an alternative `:us`
  variant that can be used. See `Localize.Number.Symbol.number_symbols_for/2`
  for the symbols supported for a given locale and number system.

* `:dti_type` specifies the digital token type when the currency code
  is a digital token short name or long name that maps to more than one
  token identifier. One of `:native`, `:auxiliary`, `:distributed`, or
  `:fungible`. When not specified, the lookup tries each type in priority
  order: `:native`, `:auxiliary`, `:distributed`, `:fungible`. The first
  match wins. This option is only relevant for digital tokens and is
  ignored for ISO 4217 currencies.

* Any other options are considered as formatting options to
  be applied by default when calling `Money.to_string/2`.

Note that the `currency_code` and `amount` arguments can be supplied in
either order,

### Examples

    iex> Money.new(:USD, 100)
    Money.new(:USD, "100")

    iex> Money.new(100, :USD)
    Money.new(:USD, "100")

    iex> Money.new("USD", 100)
    Money.new(:USD, "100")

    iex> Money.new("thb", 500)
    Money.new(:THB, "500")

    iex> Money.new("EUR", Decimal.new(100))
    Money.new(:EUR, "100")

    iex> Money.new(:EUR, "100.30")
    Money.new(:EUR, "100.30")

    iex> Money.new(:EUR, "100.30", fractional_digits: 4)
    Money.new(:EUR, "100.30", fractional_digits: 4)

    iex> Money.new(:XYZZ, 100)
    {:error, {Money.UnknownCurrencyError, "The currency :XYZZ is not known."}}

    iex> Money.new("1.000,99", :EUR, locale: "de")
    Money.new(:EUR, "1000.99")

    iex> Money.new 123.445, :USD
    {:error,
     {Money.InvalidAmountError,
      "Float amounts are not supported in new/2 due to potential " <>
      "rounding and precision issues.  If absolutely required, " <>
      "use Money.from_float/2"}}

# `new!`

```elixir
@spec new!(
  amount() | currency_reference(),
  amount() | currency_reference(),
  Keyword.t()
) :: t() | no_return()
```

Returns a `t:Money.t/0` from a currency code and a currency amount. Raises an
exception if the current code is invalid.

### Arguments

* `currency_code` is an [ISO4217](https://en.wikipedia.org/wiki/ISO_4217)
  binary or atom currency code or an
  [ISO 24165](https://www.iso.org/standard/80601.html) token identifier or shortname.

* `amount` is an integer, float or Decimal

* `options` is a keyword list of options. See `Money.new/3`.

### Examples

    Money.new!(:XYZZ, 100)
    ** (Money.UnknownCurrencyError) Currency :XYZZ is not known
      (ex_money) lib/money.ex:177: Money.new!/2

# `normalize`
*since 5.0.0* 

```elixir
@spec normalize(t()) :: t()
```

Normalizes the underlying decimal amount in a
given `t:Money.t/0`.

This will normalize the coefficient and exponent of the
decimal amount in a standard way that may aid in
native comparison of `t:Money.t/0` items.

## Example

    iex> x = %Money{currency: :USD, amount: %Decimal{sign: 1, coef: 42, exp: 0}}
    Money.new(:USD, "42")
    iex> y = %Money{currency: :USD, amount: %Decimal{sign: 1, coef: 4200000000, exp: -8}}
    Money.new(:USD, "42.00000000")
    iex> x == y
    false
    iex> y = Money.normalize(x)
    Money.new(:USD, "42")
    iex> x == y
    true

# `parse`
*since 3.2.0* 

```elixir
@spec parse(String.t(), Keyword.t()) :: t() | {:error, {module(), String.t()}}
```

Parse a string and return a `t:Money.t/0` or an error.

The string to be parsed is required to have a currency
code and an amount.  The currency code may be placed
before the amount or after, but not both.

Parsing is strict.  Additional text surrounding the
currency code and amount will cause the parse to
fail.

### Arguments

* `string` is a string to be parsed

* `options` is a keyword list of options that is
  passed to `Money.new/3` with the exception of
  the options listed below

### Options

* `:locale` is any valid locale returned by `Localize.supported_locales/0`
  or a `Localize.LanguageTag` struct.
  The default is `Localize.get_locale/0`.

* `:only` is an `atom` or list of `atoms` representing the
  currencies or currency types to be considered for a match.
  The equates to a list of acceptable currencies for parsing.
  See the notes below for currency types.

* `:except` is an `atom` or list of `atoms` representing the
  currencies or currency types to be not considered for a match.
  This equates to a list of unacceptable currencies for parsing.
  See the notes below for currency types.

* `:fuzzy` is a float greater than `0.0` and less than or
  equal to `1.0` which is used as input to the
  `String.jaro_distance/2` to determine is the provided
  currency string is *close enough* to a known currency
  string for it to identify definitively a currency code.
  It is recommended to use numbers greater than `0.8` in
  order to reduce false positives.

* `:default_currency` is any valid currency code or `false`
  that will used if no currency code, symbol or description is
  indentified in the parsed string. The default is `nil`
  which means that the default currency associated with
  the `:locale` option will be used. If `false` then the
  currency assocated with the `:locale` option will not be
  used and an error will be returned if there is no currency
  in the string being parsed.

### Returns

* a `t:Money.t/0` if parsing is successful or

* `{:error, {exception, reason}}` if an error is
  detected.

### Notes

The `:only` and `:except` options accept a list of
currency codes and/or currency types.  The following
types are recognised.

If both `:only` and `:except` are specified,
the `:except` entries take priority - that means
any entries in `:except` are removed from the `:only`
entries.

  * `:all`, the default, considers all currencies.

  * `:current` considers those currencies that have a `:to`
    date of nil and which also is a known ISO4217 currency.

  * `:historic` is the opposite of `:current`.

  * `:tender` considers currencies that are legal tender.

  * `:unannotated` considers currencies that don't have
    "(some string)" in their names.  These are usually
    financial instruments.

### Examples

    iex> Money.parse("USD 100")
    Money.new(:USD, "100")

    iex> Money.parse "USD 100,00", locale: "de"
    Money.new(:USD, "100.00")

    iex> Money.parse("100 USD")
    Money.new(:USD, "100")

    iex> Money.parse("100 eurosports", fuzzy: 0.8)
    Money.new(:EUR, "100")

    iex> Money.parse("100", default_currency: :EUR)
    Money.new(:EUR, "100")

    iex> Money.parse("100 eurosports", fuzzy: 0.9)
    {:error, {Money.UnknownCurrencyError, "The currency \"eurosports\" is unknown or not supported"}}

    iex> Money.parse("100 afghan afghanis")
    Money.new(:AFN, "100")

    iex> Money.parse("100", default_currency: false)
    {:error, {Money.Invalid,
      "A currency code, symbol or description must be specified but was not found in \"100\""}}

    iex> Money.parse("USD 100 with trailing text")
    {:error, {Money.ParseError, "Could not parse \"USD 100 with trailing text\"."}}

# `positive?`
*since 5.10.0* 

```elixir
@spec positive?(t()) :: boolean()
```

Returns a boolean indicating if `t:Money.t/0`
has a positive value.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`

### Example

    iex> Money.positive?(Money.new(:USD, 1))
    true

    iex> Money.positive?(Money.new(:USD, 0))
    false

    iex> Money.positive?(Money.new(:USD, -1))
    false

# `put_format_options`
*since 5.5.0* 

```elixir
@spec put_format_options(t(), Keyword.t()) :: t()
```

Add format options to a `t:Money.t/0`.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

* `options` is a keyword list of options. These
  options are used when calling `Money.to_string/2`.
  The default is `[]`.

# `put_fraction`

Set the fractional part of a `Money`.

### Arguments

* `money` is any `t:Money.t/0`.

* `fraction` is an integer amount that will be set
  as the fraction of the `money`.

### Notes

The fraction can only be set if it matches the number of
decimal digits for the currency associated with the `money`.
Therefore, for a currency with 2 decimal digits, the
maximum for `fraction` is `99`.

### Examples

    iex> Money.put_fraction Money.new(:USD, "2.49"), 99
    Money.new(:USD, "2.99")

    iex> Money.put_fraction Money.new(:USD, "2.49"), 0
    Money.new(:USD, "2.0")

    iex> Money.put_fraction Money.new(:USD, "2.49"), 999
    {:error,
     {Money.InvalidAmountError, "Rounding up to 999 is invalid for currency :USD"}}

# `reduce`

> This function is deprecated. Use Money.normalize/1 instead..

# `round`

```elixir
@spec round(t(), Keyword.t()) :: t() | {:error, {module(), binary()}}
```

Round a `Money` value into the acceptable range for the requested currency.

### Arguments

* `money` is any `t:Money.t/0`.

* `options` is a keyword list of options.

### Options

  * `:rounding_mode` that defines how the number will be rounded.  See
    `Decimal.Context`.  The default is `:half_even` which is also known
    as "banker's rounding".

  * `:currency_digits` which determines the rounding increment.
    The valid options are `:cash`, `:accounting` and `:iso` or
    an integer value representing the rounding factor.  The
    default is `:iso`.

### Notes

There are two kinds of rounding applied:

1. Round to the appropriate number of currency digits.

3. Apply an appropriate rounding increment.  Most currencies
   round to the same precision as the number of decimal digits, but some
   such as `:CHF` round to a minimum such as `0.05` when its a cash
   amount. The rounding increment is applied when the option
   `:fractional_digits` is set to `:cash`.

3. Digital Tokens (crypto currencies) do not have formal definitions
   of decimal digits or rounding strategies. Therefore the `money` is
   returned unmodified.

### Examples

    iex> Money.round Money.new("123.73", :CHF), currency_digits: :cash
    Money.new(:CHF, "123.75")

    iex> Money.round Money.new("123.73", :CHF), currency_digits: 0
    Money.new(:CHF, "124")

    iex> Money.round Money.new("123.7456", :CHF)
    Money.new(:CHF, "123.75")

    iex> Money.round Money.new("123.7456", :JPY)
    Money.new(:JPY, "124")

# `split`

```elixir
@spec split(money :: t(), parts :: non_neg_integer(), options :: Keyword.t()) ::
  {t(), t()}
```

Split a `Money` value into a number of parts maintaining the currency's
precision and rounding and ensuring that the parts sum to the original
amount.

### Arguments

* `money` is any `t:Money.t/0`.

* `parts` is an integer number of parts into which the
  `money` is split.

* `options` is a keyword list of options.

### Options

* See `Money.round/2`; any options are passed to
  this function.

### Returns

* `{split_amount, remainder}` where `split_amount` is the amount
  money allocated by the split and `remainder` is the amount
  left over that could not be allocated evenly.

### Notes

Returns a tuple `{dividend, remainder}` as the function result
derived as follows:

1. Divide the money by the integer divisor.

2. Round the result of the division to the precision of the currency
  using `Money.round/2`. If the rounding mode results in a
  negative remainder, the rounding is done again using rounding mode
  `:down`.

3. Return two numbers: the result of the division and any remainder
  that could not be applied given the precision of the currency.

### Examples

    iex> Money.split(Money.new("123.5", :JPY), 3)
    {Money.new(:JPY, "41"), Money.new(:JPY, "0.5")}

    iex> Money.split(Money.new("123.4", :JPY), 3)
    {Money.new(:JPY, "41"), Money.new(:JPY, "0.4")}

    iex> Money.split(Money.new("123.7", :USD), 9)
    {Money.new(:USD, "13.74"), Money.new(:USD, "0.04")}

    iex> Money.split(Money.new(:USD, 200), 3)
    {Money.new(:USD, "66.66"), Money.new(:USD, "0.02")}

# `spread`

Proportionally spreads a given amount across the given portions with no remainder.

## Arguments

  * `amount` is any `t:Money.t/0`.

  * `portions` may be a list of `t:Money.t/0`, a list of numbers, or an integer
    into which the `money` is spread.

  * `options` is a keyword list of options, which will be applied to
    `Money.round/2`.

Returns a list of `t:Money.t/0` that is the same length (or value of the integer),
with the amount spread as evenly as the currency's smallest unit allows.
The result is derived as follows:

1. Round the amount to the currency's default precision.

2. Calculate partial sums of the given portions.

3. Starting with the last portion, calculate the expected remaining amount then
   subtract and round that portion's value from the current remaining amount.

For example, with `[2, 1]` as portions and `$1` to spread, we calculate that 2/3 of the amount
should remain after `1` receives its portion, so we subtract the unrounded Money amount of
`0.666666`, and we round the share to `$0.33`.  Then `$1.00 - 0.33` is the new remaining amount.
This approach avoids numerical instability by using the expected remaining amount,
rather than summing up values as they are doled out.

## Examples

    iex> Money.spread(Money.new(:usd, 10), [Money.new(:usd, 10), Money.new(:usd, 1)])
    [Money.new(:USD, "9.09"), Money.new(:USD, "0.91")]

    iex> Money.spread(Money.new(:usd, "2.50"), [2.5, 1, 1])
    [Money.new(:USD, "1.39"), Money.new(:USD, "0.55"), Money.new(:USD, "0.56")]

    iex> Money.spread(Money.new(:usd, 2), 3)
    [Money.new(:USD, "0.67"), Money.new(:USD, "0.66"), Money.new(:USD, "0.67")]

# `sub`

```elixir
@spec sub(money_1 :: t(), money_2 :: t()) ::
  {:ok, t()} | {:error, {module(), String.t()}}
```

Subtract one `t:Money.t/0` value struct from another.

### Options

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

* `{:ok, money}` or

* `{:error, reason}`.

## Example

    iex> Money.sub Money.new(:USD, 200), Money.new(:USD, 100)
    {:ok, Money.new(:USD, 100)}

# `sub!`

```elixir
@spec sub!(money_1 :: t(), money_2 :: t()) :: t() | none()
```

Subtract one `Money` value struct from another and raise on error.

Returns either `{:ok, money}` or `{:error, reason}`.

### Arguments

* `money_1` and `money_2` are any valid `t:Money.t/0` types returned
  by `Money.new/2`.

### Returns

* a `t:Money.t/0` struct or

* raises an exception.

### Examples

    iex> Money.sub! Money.new(:USD, 200), Money.new(:USD, 100)
    Money.new(:USD, "100")

    Money.sub! Money.new(:USD, 200), Money.new(:CAD, 500)
    ** (ArgumentError) Cannot subtract monies with different currencies. Received :USD and :CAD.

# `sum`
*since 5.3.0* 

```elixir
@spec sum(
  [t(), ...],
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: {:ok, t()} | {:error, {module(), String.t()}}
```

Sum a list of monies that may be in different
currencies.

### Arguments

* `money_list` is a list of any valid `t:Money.t/0` types returned
  by `Money.new/2`.

* `rates` is a map of exchange rates. The default is the rates
  returned by `Money.ExchangeRates.latest_rates/0`. If the
  exchange rates retriever is not running, then the default is
  `%{}`.

### Returns

* `{:ok, money}` where `money` is a `t:Money.t/0` representing the
  sum of the maybe converted money amounts. The currency of the sum is
  the currency of the first `Money` in the `money_list`.

* `{:error, {exception, reason}}` describing an error.

### Examples

    iex> Money.sum([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:USD, 50)])
    {:ok, Money.new(:USD, 350)}

    iex> Money.sum([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], %{})
    {:error,
     {Money.ExchangeRateError, "No exchange rate is available for currency :AUD"}}

    iex> rates = %{AUD: Decimal.new(2), USD: Decimal.new(1)}
    iex> Money.sum [Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], rates
    {:ok, Money.new(:USD, "325.0")}

# `sum!`

```elixir
@spec sum!(
  [t(), ...],
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: t() | no_return()
```

Sum a list of monies that may be in different
currencies or raise an exception on error.

### Arguments

* `money_list` is a list of any valid `t:Money.t/0` types returned
  by `Money.new/2`.

* `rates` is a map of exchange rates. The default is the rates
  returned by `Money.ExchangeRates.latest_rates/0`. If the
  exchange rates retriever is not running, then the default is
  `%{}`.

### Returns

* A `t:Money.t/0`  representing the sum of the maybe
  converted money amounts. The currency of the sum is
  the currency of the first `Money` in the `money_list`.

* raises an exception.

### Examples

    iex> Money.sum!([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:USD, 50)])
    Money.new(:USD, 350)

    iex> Money.sum!([Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], %{})
    ** (Money.ExchangeRateError) No exchange rate is available for currency :AUD

    iex> rates = %{AUD: Decimal.new(2), USD: Decimal.new(1)}
    iex> Money.sum! [Money.new(:USD, 100), Money.new(:USD, 200), Money.new(:AUD, 50)], rates
    Money.new(:USD, "325.0")

# `to_currency`

```elixir
@spec to_currency(
  t(),
  currency_reference(),
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: {:ok, t()} | {:error, {module(), String.t()}}
```

Convert `money` from one currency to another.

### Arguments

* `money` is any `t:Money.t/0` struct returned by `Money.Currency.new/2`.

* `to_currency` is a valid currency code into which the `money` is converted.

* `rates` is a `Map` of currency rates where the map key is an upcased
  atom or string and the value is a Decimal conversion factor.  The default is the
  latest available exchange rates returned from `Money.ExchangeRates.latest_rates/0`.

### Converting to a currency defined in a locale

To convert a `Money` to a currency defined by a locale,
`Localize.Currency.currency_from_locale/1` can be called with
a `t:Localize.LanguageTag.t/0` parameter. It will return
the currency configured for that locale.

### Examples

    iex> Money.to_currency(Money.new(:USD, 100), :AUD,
    ...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
    {:ok, Money.new(:AUD, "73.4500")}

    iex> Money.to_currency(Money.new("USD", 100), "AUD",
    ...>   %{"USD" => Decimal.new(1), "AUD" => Decimal.from_float(0.7345)})
    {:ok, Money.new(:AUD, "73.4500")}

    iex> Money.to_currency(Money.new(:USD, 100), :AUDD,
    ...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
    {:error, {Money.UnknownCurrencyError, "The currency :AUDD is not known."}}

    iex> Money.to_currency(Money.new(:USD, 100), :CHF,
    ...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)})
    {:error, {Money.ExchangeRateError,
      "No exchange rate is available for currency :CHF"}}

# `to_currency!`

```elixir
@spec to_currency!(
  t(),
  currency_reference(),
  Money.ExchangeRates.t()
  | {:ok, Money.ExchangeRates.t()}
  | {:error, {module(), String.t()}}
) :: t() | no_return()
```

Convert `money` from one currency to another or raises on error.

### Arguments

* `money` is any `t:Money.t/0` struct returned by `Money.Currency.new/2`.

* `to_currency` is a valid currency code into which the `money` is converted.

* `rates` is a `Map` of currency rates where the map key is an upcased
  atom or string and the value is a Decimal conversion factor.  The default is the
  latest available exchange rates returned from `Money.ExchangeRates.latest_rates/0`.

### Examples

    iex> Money.to_currency! Money.new(:USD, 100), :AUD,
    ...>   %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
    Money.new(:AUD, "73.4500")

    iex> Money.to_currency! Money.new("USD", 100), "AUD",
    ...>   %{"USD" => Decimal.new(1), "AUD" => Decimal.from_float(0.7345)}
    Money.new(:AUD, "73.4500")

    => Money.to_currency! Money.new(:USD, 100), :ZZZ,
         %{USD: Decimal.new(1), AUD: Decimal.from_float(0.7345)}
    ** (Money.UnknownCurrencyError) The currency :ZZZ is not known.

# `to_currency_code`
*since 5.6.0* 

```elixir
@spec to_currency_code(money :: t()) :: atom()
```

Returns the currecny code of a `Money` type
as an `atom`.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

### Returns

* the currency code as an `t:atom`.

## Example

    iex> m = Money.new("USD", 100)
    iex> Money.to_currency_code(m)
    :USD

# `to_decimal`

```elixir
@spec to_decimal(money :: t()) :: Decimal.t()
```

Returns the amount part of a `Money` type as a `Decimal`.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

### Returns

* a `Decimal.t`.

## Example

    iex> m = Money.new("USD", 100)
    iex> Money.to_decimal(m)
    Decimal.new(100)

# `to_integer_exp`

Returns a tuple comprising the currency code, integer amount,
exponent and remainder.

Some services require submission of money items as an integer
with an implied exponent that is appropriate to the currency.

Rather than return only the integer, `Money.to_integer_exp`
returns the currency code, integer, exponent and remainder.
The remainder is included because to return an integer
money with an implied exponent the `Money` has to be rounded
potentially leaving a remainder.

### Options

* `money` is any `t:Money.t/0` struct returned by `Money.Currency.new/2`.

### Notes

* Since the returned integer is expected to have the implied fractional
  digits the `Money` needs to be rounded which is what this function does.

### Example

    iex> m = Money.new(:USD, "200.012356")
    Money.new(:USD, "200.012356")
    iex> Money.to_integer_exp(m)
    {:USD, 20001, -2, Money.new(:USD, "0.002356")}

    iex> m = Money.new(:USD, "200.00")
    Money.new(:USD, "200.00")
    iex> Money.to_integer_exp(m)
    {:USD, 20000, -2, Money.new(:USD, "0.00")}

# `to_string`

```elixir
@spec to_string(t(), Keyword.t() | map()) ::
  {:ok, String.t()} | {:error, {module(), String.t()}} | {:error, Exception.t()}
```

Returns a formatted string representation of a `t:Money.t/0`.

Formatting is performed according to the rules defined by CLDR. See
`Localize.Number.to_string/2` for formatting options.  The default is to format
as a currency which applies the appropriate rounding and fractional digits
for the currency.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

* `options` is a keyword list, or a validated options struct accepted by
  `Localize.Number.to_string/2`.

### Returns

* `{:ok, string}` or

* `{:error, reason}`.

### Options

* `currency_symbol`: Allows overriding a currency symbol. The alternatives
  are:
  * `:iso` the ISO currency code will be used instead of the default
    currency symbol.
  * `:narrow` uses the narrow symbol defined for the locale. The same
    narrow symbol can be defined for more than one currency and therefore this
    should be used with care. If no narrow symbol is defined, the standard
    symbol is used.
  * `:symbol` uses the standard symbol defined in CLDR. A symbol is unique
    for each currency and can be safely used.
  * "string" uses `string` as the currency symbol
  * `:standard` (the default and recommended) uses the CLDR-defined symbol
    based upon the currency format for the locale.
  * `:none` means format the amount without any currency symbol.

* `:no_fraction_if_integer` is a boolean which, if `true`, will set `:fractional_digits`
  to `0` if the money value is an integer value.

* Any other options are passed to `Localize.Number.to_string/2`.

### Examples

    iex> Money.to_string Money.new(:USD, 1234)
    {:ok, "$1,234.00"}

    iex> Money.to_string Money.new(:USD, 1234), no_fraction_if_integer: true
    {:ok, "$1,234"}

    iex> Money.to_string Money.new(:JPY, 1234)
    {:ok, "¥1,234"}

    iex> Money.to_string Money.new(:THB, 1234)
    {:ok, "THB 1,234.00"}

    iex> Money.to_string Money.new(:THB, 1234, fractional_digits: 4)
    {:ok, "THB 1,234.0000"}

    iex> Money.to_string Money.new(:USD, 1234), format: :long
    {:ok, "1,234 US dollars"}

    iex> Money.to_string(Money.new(:EUR, "100"), locale: "bn")
    {:ok, "১০০.০০€"}

# `to_string!`

```elixir
@spec to_string!(t(), Keyword.t() | map()) :: String.t() | no_return()
```

Returns a formatted string representation of a `t:Money.t/0` or raises if
there is an error.

Formatting is performed according to the rules defined by CLDR. See
`Localize.Number.to_string/2` for formatting options.  The default is to format
as a currency which applies the appropriate rounding and fractional digits
for the currency.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`.

* `options` is a keyword list, or a validated options struct accepted by
  `Localize.Number.to_string/2`.

### Options

* Any other options are passed to `Localize.Number.to_string/2`.

### Examples

    iex> Money.to_string! Money.new(:USD, 1234)
    "$1,234.00"

    iex> Money.to_string! Money.new(:JPY, 1234)
    "¥1,234"

    iex> Money.to_string! Money.new(:THB, 1234)
    "THB 1,234.00"

    iex> Money.to_string! Money.new(:USD, 1234), format: :long
    "1,234 US dollars"

# `within?`
*since 5.18.0* 

```elixir
@spec within?(money :: t(), minimum :: t(), maximum :: t()) :: boolean()
```

Returns a boolean indicating if the `t:Money.t/0` is in the
range `minimum..maximum`.

#### Arguments

* `money`, `minimum` and `maximum` are any valid `t:Money.t/0` types returned
  by `Money.new/2`. They should be of the same currency.

#### Returns

* `true` or `false`.

#### Examples

    iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 50), Money.new(:USD, 200))
    true

    iex> Money.within?(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 200))
    false

    iex> Money.within?(Money.new(:USD, 10), Money.new(:USD, 50), Money.new(:USD, 50))
    false

    iex> Money.within?(Money.new(:USD, 50), Money.new(:USD, 50), Money.new(:USD, 50))
    true

    iex> Money.within?(Money.new(:USD, 100), Money.new(:USD, 300), Money.new(:USD, 200))
    ** (ArgumentError) Minimum must be less than maximum. Found Money.new(:USD, "300") and Money.new(:USD, "200")

    iex> Money.within?(Money.new(:USD, 10), Money.new(:AUD, 300), Money.new(:EUR, 200))
    ** (ArgumentError) Cannot compare monies with different currencies. Received :USD, :AUD and :EUR

# `zero`

```elixir
@spec zero(currency_reference() | t(), Keyword.t()) ::
  t() | {:error, {module(), binary()}}
```

Return a zero amount `t:Money.t/0` in the given currency.

### Arguments

* `money_or_currency` is either a `t:Money.t/0` or
  a currency code.

* `options` is a keyword list of options passed
  to `Money.new/3`. The default is `[]`.

### Example

    iex> Money.zero(:USD)
    Money.new(:USD, "0")

    iex> money = Money.new(:USD, 200)
    iex> Money.zero(money)
    Money.new(:USD, "0")

    iex> Money.zero :ZZZ
    {:error, {Money.UnknownCurrencyError, "The currency :ZZZ is not known."}}

# `zero?`
*since 5.10.0* 

```elixir
@spec zero?(t()) :: boolean()
```

Returns a boolean indicating if `t:Money.t/0`
has a zero value.

### Arguments

* `money` is any valid `t:Money.t/0` type returned
  by `Money.new/2`

### Example

    iex> Money.zero?(Money.new(:USD, 0))
    true

    iex> Money.zero?(Money.new(:USD, 1))
    false

    iex> Money.zero?(Money.new(:USD, -1))
    false

---

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