# # Ratio Math Functions

These functions let you apply a ratio (a fraction) to an amount, multiplying or
dividing an amount by a ratio of two natural numbers. Ratios consist of a
*numerator* and a *denominator*. Both of these consist of a value and a brand,
just like `amounts`

. A ratio cannot have a denominator value of 0.

The ratio functions have to be imported.

The most common kind of `Ratio`

is applied to an `Amount`

of a particular brand
and produces results of the same brand.

`Ratios`

can also have two brands, essentially typing them such as miles per
hour or US dollars for Swiss francs (an exchange rate ratio) (i.e. the numerator
is one brand and the denominator is another). Keep in mind that a ratio function
should make sense when used with a dual-branded ratio.

For example, when multiplying an amount by a ratio, the result has the ratio numerator's brand. So the amount should have the same brand as the ratio's denominator to cancel it out; e.g. 5 gallons * (10 miles / 1 gallon) = 50 miles. Similarly, dividing an amount by a ratio returns a result amount with the denominator's brand, so the amount should be the same brand as the numerator to cancel it out.

In order to support precision calculations, the multiplication and division operations require that the caller specify whether the result should be rounded up or down. These operations produce Amounts, so they have to end by converting the ratio to an integer with a division. This may require roundoff, and correct calculations require that the caller choose which is appropriate.

## # `makeRatio(numerator, numeratorBrand, denominator, denominatorBrand)`

`numerator`

:`{ BigInt }`

`numeratorBrand`

:`{ Brand }`

`denominator`

:`{ BigInt }`

defaults to 100n`denominatorBrand)`

:`{ Brand }`

defaults to`numeratorBrand`

value- Returns:
`{ numerator: { Value , Brand }, denominator: { Value, Brand } }`

Makes a `Ratio`

, representing a fraction and consisting of a record containing
two `Amounts`

. It is a pass-by-copy record.

By default, the `denominator`

is 100; i.e. the ratio is a percent.

By default, the `denominatorBrand`

value is the same as the `numeratorBrand`

value.

A ratio has these restrictions:

- Both the numerator value and denominator value must be natural numbers.
- The denominator cannot be 0.

```
// Use default values to create a ratio of 50 / 100 Quatloos
const ratio = makeRatio(50n, quatloosBrand);
// Specify all values to create a ratio of 75 Quatloos / 4 Moolas (the current exchange rate)
const ratio = makeRatio(75n, quatloosBrand, 4n, moolasBrand);
```

## # `makeRatioFromAmounts(numeratorAmount, denominatorAmount)`

`numeratorAmount`

:`{ Amount }`

`denominatorAmount`

:`{ Amount }`

- Returns:
`{ numerator: { value , brand }, denominator: { value, brand } }`

Makes a `Ratio`

, representing a fraction and consisting of an immutable pair
of two `Amounts`

. The `numeratorAmount`

is the ratio's numerator and
the `denominatorAmount`

is the ratio's denominator. It is a pass-by-copy
record.

A ratio has these restrictions:

- Both the numerator value and denominator value must be natural numbers.
- The denominator cannot be 0.

```
const fiftyCents = AmountMath.make(centsBrand, 50n);
const dollar = AmountMath.make(centsBrand, 100n);
const halfADollar = makeRatioFromAmounts(fiftyCents, dollar);
```

## # `assertIsRatio(ratio)`

`ratio`

:`{ Record }`

- Returns:
`void`

Throws an error if the argument is not a valid ratio.

Throws messages for errors:

`Ratio ${ratio} must be a record with 2 fields.`

`Parameter must be a Ratio record, but ${ratio} has ${q(name)}`

```
assertIsRatio(aRatio);
```

## # `floorMultiplyBy(amount, ratio)`

## # `ceilMultiplyBy(amount, ratio)`

`amount`

:`{ Amount }`

`ratio`

:`{ Ratio }`

- Returns:
`{ Amount }`

Returns an immutable `Amount`

. Its brand is the `ratio`

's *numerator*'s brand.
Note the denominator brand has to be the same as the amount brand.

The resulting value is determined by:

- Multiplying the
`amount`

value by the`ratio`

's numerator's value. - Dividing the result from step 1 by the
`ratio`

's denominator's value. - If that results in an integer, that value is returned, otherwise, the value is rounded down (for floorMultiplyBy) or up (for ceilMultiplyBy) to the next integer.

For example, if the amount value is 47 and the ratio is 3 / 5, the calculation would go

- 47 * 3 = 141
- 141 / 5 = 28.2
- Floor(28.2) = 28

If the numerator's brand was Swiss francs, the result would be an `Amount`

of
28 Swiss francs.

Throws errors with messages:

`Expected an amount: ${amount})`

: First argument isn't an`Amount`

.`amount's brand ${q(amount.brand)} must match ratio's denominator ${q( ratio.denominator.brand`

: The amount and ratio's denominator must have the same brand.

```
const exchangeRatio = makeRatio(3n, swissFrancBrand, 5n, usDollarBrand);
const Dollars47 = AmountMath.make(dollarBrand, 47n);
// Returns an amount of 28 Swiss francs
const exchange = multiplyBy(Dollars100, exchangeRatio);
```

## # `floorDivideBy(amount, ratio)`

## # `ceilDivideBy(amount, ratio)`

`amount`

:`{ Amount }`

`ratio`

:`{ Ratio }`

- Returns:
`{ Amount }`

Returns an immutable `Amount`

. Its brand is the `ratio`

's *denominator*'s brand.

The resulting value is determined by:

- Multiplying the
`amount`

value by the`ratio`

's denominator's value. - Dividing the result from step 1 by the
`ratio`

's numerator's value. - If that results in an integer, that value is returned, otherwise, the value is rounded down (for floorDivideBy) or up (for ceilDivideBy) to the next integer.

For example, if the amount value is 47 and the ratio is 3 / 5, the calculation would go

- 47 * 5 = 235
- 235 / 3 = 78.33333...
- Floor(78.3333...) = 78

If the denominator's brand was US dollars, the result would be an `Amount`

of
78 US dollars.

Throws errors with messages:

`Expected an amount: ${amount})`

: First argument isn't an`Amount`

.`amount's brand ${q(amount.brand)} must match ratio's numerator ${q(ratio.numerator.brand`

: The amount and ratio's numerator must have the same brand.

```
```js
const exchangeRatio = makeRatio(3n, swissFrancBrand, 5n, usDollarBrand);
const Dollars47 = AmountMath.make(dollarBrand, 47n);
// Returns an amount of 78 Swiss francs
const exchange = divideBy(Dollars100, exchangeRatio);
```

## # `invertRatio(ratio)`

`ratio`

:`{ Ratio }`

- Returns:
`{ Ratio }`

Returns a `Ratio`

such that the `ratio`

argument's numerator is the returned value's
denominator and the `ratio`

argument's denominator is the returned value's numerator.

```
const exchangeRatio = makeRatio(3n, swissFrancBrand, 5n, usDollarBrand);
// Returns a ratio of 5 US dollars / 3 swiss Francs
const invertedRatio = invertRatio(exchangeRatio);
```