# `Localize.Unit.Math`
[🔗](https://github.com/elixir-localize/localize/blob/v0.39.0/lib/localize/unit/math.ex#L1)

Arithmetic operations on `Localize.Unit` structs.

All functions operate on unit structs that have a value.

`add` and `sub` require convertible units (same dimensional base unit)
and return a result in the first argument's unit type.

`mult` and `div` with two units produce a new compound unit by
combining their dimensions. For example, `meter * second` produces
`meter-second`, and `meter / second` produces `meter-per-second`.

# `abs`

```elixir
@spec abs(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Returns the absolute value of a unit.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the absolute value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(-5, "meter")
    iex> {:ok, result} = Localize.Unit.Math.abs(u)
    iex> result.value
    5

# `acos`

```elixir
@spec acos(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the arc cosine of a dimensionless unit value.

# `acosh`

```elixir
@spec acosh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the inverse hyperbolic cosine of a dimensionless unit value.

# `add`

```elixir
@spec add(Localize.Unit.t(), Localize.Unit.t()) ::
  {:ok, Localize.Unit.t()} | {:error, Exception.t() | String.t()}
```

Adds two convertible units together.

The value of `unit_2` is converted to the unit type of `unit_1`
before addition. The result has the same unit type as `unit_1`.

### Arguments

* `unit_1` is a `%Localize.Unit{}` struct with a value.

* `unit_2` is a `%Localize.Unit{}` struct with a value, convertible with `unit_1`.

### Returns

* `{:ok, unit}` with the summed value in `unit_1`'s unit type, or

* `{:error, reason}` if the units are not convertible.

### Examples

    iex> {:ok, a} = Localize.Unit.new(1, "kilometer")
    iex> {:ok, b} = Localize.Unit.new(500, "meter")
    iex> {:ok, result} = Localize.Unit.Math.add(a, b)
    iex> result.value
    1.5
    iex> result.name
    "kilometer"

# `apply_dimensionless`

```elixir
@spec apply_dimensionless(atom(), Localize.Unit.t()) ::
  {:ok, number()} | {:error, String.t()}
```

Applies a trigonometric, hyperbolic, or transcendental function to
a dimensionless unit value.

The unit must be dimensionless — its base unit must reduce to an
angle (`revolution`) or a ratio (`part`). Units with physical
dimensions (length, mass, etc.) are rejected.

Supported function names: `:sin`, `:cos`, `:tan`, `:asin`, `:acos`, `:atan`, `:exp`, `:sinh`, `:cosh`, `:tanh`, `:asinh`, `:acosh`, `:atanh`, `:ln`, `:log`, `:log2`.

### Arguments

* `name` is an atom naming the function.

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, number}` with the function result.

* `{:error, reason}` if the unit is not dimensionless or has no value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(0, "radian")
    iex> {:ok, result} = Localize.Unit.Math.apply_dimensionless(:sin, u)
    iex> result
    0.0

# `asin`

```elixir
@spec asin(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the arc sine of a dimensionless unit value.

# `asinh`

```elixir
@spec asinh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the inverse hyperbolic sine of a dimensionless unit value.

# `atan`

```elixir
@spec atan(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the arc tangent of a dimensionless unit value.

# `atanh`

```elixir
@spec atanh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the inverse hyperbolic tangent of a dimensionless unit value.

# `cbrt`

```elixir
@spec cbrt(Localize.Unit.t()) ::
  {:ok, Localize.Unit.t() | number()} | {:error, String.t()}
```

Computes the cube root of a unit.

The unit must have powers divisible by 3 on all dimension components.
For example, `cbrt(27 cubic-meter)` produces `3 meter`.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the cube root of the value and divided unit
  powers, or

* `{:error, reason}` if any dimension has a power not divisible by 3.

### Examples

    iex> {:ok, u} = Localize.Unit.new(27, "cubic-meter")
    iex> {:ok, result} = Localize.Unit.Math.cbrt(u)
    iex> result.value
    3.0
    iex> result.name
    "meter"

# `ceil`

```elixir
@spec ceil(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Rounds the value of a unit up to the nearest integer.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the ceiling value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(3.2, "meter")
    iex> {:ok, result} = Localize.Unit.Math.ceil(u)
    iex> result.value
    4

# `cos`

```elixir
@spec cos(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the cosine of a dimensionless unit value.

# `cosh`

```elixir
@spec cosh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the hyperbolic cosine of a dimensionless unit value.

# `div`

```elixir
@spec div(Localize.Unit.t(), number() | Decimal.t() | Localize.Unit.t()) ::
  {:ok, Localize.Unit.t() | number() | Decimal.t()}
  | {:error, Exception.t() | String.t()}
```

Divides a unit by a scalar number or another unit.

When the second argument is a number, the unit's value is divided
by that number. When it is a unit, the values are divided and a
new compound unit is produced by combining the dimensions. For
example, `meter / second` produces `meter-per-second`.

When both operands share the same base dimension, the second
operand is first converted to the first operand's unit, then the
dimensions cancel and the result is returned as a bare
dimensionless scalar. So `kilometer / meter` yields a number, not
a compound unit.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

* `divisor` is a numeric scalar (integer, float, or Decimal)
  or a `%Localize.Unit{}` struct.

### Returns

* `{:ok, unit}` with the quotient value and combined unit type, or

* `{:error, reason}` if the resulting unit name cannot be parsed.

### Examples

    iex> {:ok, u} = Localize.Unit.new(10, "meter")
    iex> {:ok, result} = Localize.Unit.Math.div(u, 2)
    iex> result.value
    5.0

    iex> {:ok, a} = Localize.Unit.new(100, "meter")
    iex> {:ok, b} = Localize.Unit.new(10, "second")
    iex> {:ok, result} = Localize.Unit.Math.div(a, b)
    iex> result.value
    10.0
    iex> result.name
    "meter-per-second"

# `exp`

```elixir
@spec exp(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes e^x for a dimensionless unit value.

# `floor`

```elixir
@spec floor(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Rounds the value of a unit down to the nearest integer.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the floor value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(3.7, "meter")
    iex> {:ok, result} = Localize.Unit.Math.floor(u)
    iex> result.value
    3

# `invert`

```elixir
@spec invert(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Inverts a unit.

For a simple unit like `meter`, the result is `per-meter` with
value `1 / original_value`. For a per-unit like `meter-per-second`,
the numerator and denominator are swapped to produce
`second-per-meter`.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the inverted unit and value, or

* `{:error, reason}` if the unit cannot be inverted.

### Examples

    iex> {:ok, u} = Localize.Unit.new(4, "meter-per-second")
    iex> {:ok, inv} = Localize.Unit.Math.invert(u)
    iex> inv.name
    "second-per-meter"
    iex> inv.value
    0.25

# `ln`

```elixir
@spec ln(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the natural logarithm of a dimensionless unit value.

# `log2`

```elixir
@spec log2(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the base-2 logarithm of a dimensionless unit value.

# `log`

```elixir
@spec log(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the base-10 logarithm of a dimensionless unit value.

# `mult`

```elixir
@spec mult(Localize.Unit.t(), number() | Decimal.t() | Localize.Unit.t()) ::
  {:ok, Localize.Unit.t() | number() | Decimal.t()}
  | {:error, Exception.t() | String.t()}
```

Multiplies a unit by a scalar number or another unit.

When the second argument is a number, the unit's value is scaled.
When it is a unit, the values are multiplied and a new compound
unit is produced by combining the dimensions. For example,
`meter * second` produces `meter-second`.

When both operands share the same base dimension (e.g. both are
lengths), the second operand is first converted to the first
operand's unit, then the result is consolidated into a squared
(or higher-power) form. So `millimeter * meter` produces
`square-millimeter`, not `millimeter-meter`.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

* `multiplier` is a numeric scalar (integer, float, or Decimal)
  or a `%Localize.Unit{}` struct.

### Returns

* `{:ok, unit}` with the product value and combined unit type, or

* `{:error, reason}` if the resulting unit name cannot be parsed.

### Examples

    iex> {:ok, u} = Localize.Unit.new(5, "meter")
    iex> {:ok, result} = Localize.Unit.Math.mult(u, 3)
    iex> result.value
    15

    iex> {:ok, a} = Localize.Unit.new(10, "meter")
    iex> {:ok, b} = Localize.Unit.new(5, "second")
    iex> {:ok, result} = Localize.Unit.Math.mult(a, b)
    iex> result.value
    50
    iex> result.name
    "meter-second"

# `negate`

```elixir
@spec negate(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Negates the value of a unit.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the negated value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(5, "meter")
    iex> {:ok, neg} = Localize.Unit.Math.negate(u)
    iex> neg.value
    -5

# `round`

```elixir
@spec round(Localize.Unit.t(), non_neg_integer(), atom()) ::
  {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Rounds the value of a unit to the nearest integer or to the
specified number of decimal places using the given rounding mode.

Float inputs are routed through `Decimal` so every mode produces
consistent results; the return value preserves the input value's
numeric type (float in / float out, Decimal in / Decimal out,
integer in / integer out).

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

* `places` is the number of decimal places to round to. Defaults to 0.

* `mode` is the rounding mode. One of `:half_up` (default),
  `:half_even`, `:half_down`, `:up`, `:down`, `:ceiling`, or `:floor`.

### Returns

* `{:ok, unit}` with the rounded value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(3.7, "kilogram")
    iex> {:ok, result} = Localize.Unit.Math.round(u)
    iex> result.value
    4.0

    iex> {:ok, u} = Localize.Unit.new(2.5, "kilogram")
    iex> {:ok, result} = Localize.Unit.Math.round(u, 0, :half_even)
    iex> result.value
    2.0

# `sin`

```elixir
@spec sin(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the sine of a dimensionless unit value (angle or ratio).

### Examples

    iex> {:ok, u} = Localize.Unit.new(0, "radian")
    iex> {:ok, result} = Localize.Unit.Math.sin(u)
    iex> result
    0.0

# `sinh`

```elixir
@spec sinh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the hyperbolic sine of a dimensionless unit value.

# `sqrt`

```elixir
@spec sqrt(Localize.Unit.t()) ::
  {:ok, Localize.Unit.t() | number()} | {:error, String.t()}
```

Computes the square root of a unit.

The unit must have even powers on all dimension components.
For example, `sqrt(9 square-meter)` produces `3 meter`, but
`sqrt(9 cubic-meter)` returns an error.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the square root of the value and halved unit
  powers, or

* `{:error, reason}` if any dimension has an odd power.

### Examples

    iex> {:ok, u} = Localize.Unit.new(9, "square-meter")
    iex> {:ok, result} = Localize.Unit.Math.sqrt(u)
    iex> result.value
    3.0
    iex> result.name
    "meter"

# `sub`

```elixir
@spec sub(Localize.Unit.t(), Localize.Unit.t()) ::
  {:ok, Localize.Unit.t()} | {:error, Exception.t() | String.t()}
```

Subtracts `unit_2` from `unit_1`.

The value of `unit_2` is converted to the unit type of `unit_1`
before subtraction. The result has the same unit type as `unit_1`.

### Arguments

* `unit_1` is a `%Localize.Unit{}` struct with a value.

* `unit_2` is a `%Localize.Unit{}` struct with a value, convertible with `unit_1`.

### Returns

* `{:ok, unit}` with the difference in `unit_1`'s unit type, or

* `{:error, reason}` if the units are not convertible.

### Examples

    iex> {:ok, a} = Localize.Unit.new(1, "kilometer")
    iex> {:ok, b} = Localize.Unit.new(200, "meter")
    iex> {:ok, result} = Localize.Unit.Math.sub(a, b)
    iex> result.value
    0.8
    iex> result.name
    "kilometer"

# `tan`

```elixir
@spec tan(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the tangent of a dimensionless unit value.

# `tanh`

```elixir
@spec tanh(Localize.Unit.t()) :: {:ok, number()} | {:error, String.t()}
```

Computes the hyperbolic tangent of a dimensionless unit value.

# `trunc`

```elixir
@spec trunc(Localize.Unit.t()) :: {:ok, Localize.Unit.t()} | {:error, Exception.t()}
```

Truncates the value of a unit toward zero.

### Arguments

* `unit` is a `%Localize.Unit{}` struct with a value.

### Returns

* `{:ok, unit}` with the truncated value.

### Examples

    iex> {:ok, u} = Localize.Unit.new(3.7, "meter")
    iex> {:ok, result} = Localize.Unit.Math.trunc(u)
    iex> result.value
    3

    iex> {:ok, u} = Localize.Unit.new(-3.7, "meter")
    iex> {:ok, result} = Localize.Unit.Math.trunc(u)
    iex> result.value
    -3

---

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