# Numbers

Numbers have two namespaces: `integer` operations take values built on
`Int`, and `decimal` operations take values built on `Decimal`. The
operators `/` and `%` are in
[Expressions and operators](expressions-and-operators.md);
these operations do what an operator can't.

| Operation | Gives | Fails | SQL form |
|---|---|---|---|
| `integer.divide(dividend, divisor, rounding:)` | `Int` ([Expressions and operators](expressions-and-operators.md)) | | every mode: `div` and `mod` with a `CASE` |
| `integer.abs(value)` | `Int`, at least 0 | overflow on the smallest `Int` is a defect | `abs(x)` |
| `integer.min(a, b)`, `integer.max(a, b)` | the smaller or larger, keeping their named type (both the same, as `+` needs) | | `LEAST(a, b)`, `GREATEST(a, b)` |
| `integer.from_decimal(value, rounding:)` | `Int`, `value` rounded to a whole number | overflow is a defect | `round(x)::bigint` for `half_up`; a `CASE` on the dropped digits for the others |
| `decimal.divide(dividend, divisor, rounding:)` | `Decimal` ([Expressions and operators](expressions-and-operators.md)) | | every mode: as `integer.divide`, on the values scaled to the dividend's places |
| `decimal.abs(value)` | `Decimal`, at least 0, the same scale | | `abs(x)` |
| `decimal.min(a, b)`, `decimal.max(a, b)` | as for `integer` | | `LEAST(a, b)`, `GREATEST(a, b)` |
| `decimal.round(value, scale:, rounding:)` | `Decimal` with at most `scale` places; `scale:` a whole number written out, at least 0 | | `x` when it has at most `s` places, where `round` would add zeros; otherwise `round(x, s)` for `half_up`, `trunc(x, s)` for `down` and a `CASE` on the dropped digits for the others |
| `decimal.sqrt(value, scale:, rounding:)` | `Decimal`; `value` never negative | | none |
| `decimal.power(value, exponent)` | `Decimal`, exact; `exponent` a whole number, never negative | overflow is a defect | none |
| `decimal.exp(value, scale:, rounding:)`, `decimal.ln(value, scale:, rounding:)` | `Decimal`; `ln`'s `value` above 0 | `ln`: `out_of_range` | none |
| `decimal.sin(radians, scale:, rounding:)`, `decimal.cos(radians, scale:, rounding:)` | `Decimal` | | none |
| `decimal.atan2(y, x, scale:, rounding:)` | `Decimal`, radians | | none |
| `decimal.pi(scale:, rounding:)` | `Decimal` | | none |

- **Rounding to a type's scale needs no call.** Building a value of a
  type with a fixed `scale` rounds it half to even
  ([Conditions as proof](creating-values.md#conditions-as-proof)), so
  `decimal.round` is for another rounding mode, or for fewer places than
  the type keeps.
- **The rounding modes.** `Rounding` has four: `half_even` takes a half to
  the even digit, `half_up` takes a half away from zero, `up` rounds away
  from zero, and `down` rounds toward zero, its SQL form `trunc`. There
  is no `floor`, `ceiling` or `half_down`.
- **An `Int` becomes a `Decimal` by multiplying,** as in `count * 1.00`,
  since `*` may mix the two
  ([Expressions and operators](expressions-and-operators.md)).
  There is no `decimal.from_integer`.
- **Parsing and formatting** work as for every standard type, through
  the contract
  ([Every standard type meets one contract](every-standard-type-meets-one-contract.md)):
  `text.parse(raw, as: Quantity)` and `text.format(n, locale:)`. Parsing
  takes only the form a number has on the wire: no grouping, no decimal
  comma, no exponent. A spreadsheet's `1.234,50` is a job for a cell
  decoder, a package's `decode:`.
- **Formatting for people** uses CLDR's decimal format for the locale,
  with its digits, grouping and decimal separator, and shows every place
  the value keeps, as a translation's `{n}` writes it
  ([Using a message](translations-as-messages.md#using-a-message)):
  `1234.50` is `1,234.50` in `en_gb` and `1.234,50` in `de_de`. It takes
  no options, so `zone:` or `format:` is `type.temporal_option_unused`. A
  `Bool` has no format for people.
- **`min` and `max` take two values of one type,** as `+` does, and give
  one of them as it is. Two named types that aren't one type after
  widening are `type.mismatch`. Where one widens to the other, the result
  has the wider type
  ([When one type can stand in for another](when-one-type-can-stand-in-for-another.md)).
  A literal takes the other value's type and is checked against all its
  rules, since the result may be the literal. A plain number, which
  carries no type of its own, makes the result the plain representation,
  and so do two literals. Of two equal values, `decimal.min` and
  `decimal.max` give the first, so `decimal.min(1.50, 1.5)` keeps
  `1.50`'s places.
- **`scale:` is a whole number from 0 to 18,** the range a type's `scale`
  takes ([Representation types](built-in-types.md#representation-types)),
  written out at the call. A value there is `type.mismatch`, as it is for
  `text.parse`'s `as:`. A literal below 0 is `type.argument_negative`, and
  any other literal that isn't a whole number up to 18 is
  `type.mismatch`. `decimal.round` gives *at most* `scale` places, so it
  keeps a value that has no more places than `scale:` as it is. The maths
  operations give exactly `scale` places: `decimal.sqrt(4.00, scale: 2,
  ...)` is `2.00`.
- **What the checker knows about results.** These facts let it prove a
  result fits a type without a check
  ([Conditions as proof](creating-values.md#conditions-as-proof)).
  `abs` is at least 0, as the table says. `min` and `max` carry their
  arguments' bounds: the smaller of two values is never above either's
  top. `integer.from_decimal` and `decimal.round` keep the sign of a value
  bounded at zero, since no mode rounds across zero. `sqrt` and `exp` are
  at least 0, and `pi` is at least 3. The checker knows nothing finer: a
  rounded value's other bounds, and anything built from `sin` or `cos`,
  which carry no bounds, need a check.
- **Arguments that must be proved.** `sqrt`'s value and `power`'s
  exponent are never negative, proved as a count is (`never_negative`),
  or the call is `type.argument_negative`. `ln` fails `out_of_range`, and
  that is settled by proof, as a construction's rule is. A literal above
  0, or a value whose type has a `min` above 0, can't fail, so its call
  takes no `attempt`; one written with an `attempt` is
  `failure.attempt_infallible`. Any other value may fail, and the call
  maps `out_of_range` or `invalid:`; its failure is `invalid_value`.
- **Edges of the maths.** `atan2(0, 0)` is 0, where no angle is meant,
  rather than a failure. `atan2(0, x)` for `x` below 0 is π, as `Decimal`
  has no negative zero to make it -π. `power(value, 0)` is 1 at `value`'s
  scale, `0^0` included, and every other power keeps the places repeated
  `*` keeps: `1.50` squared is `2.25`. A `power` past 38 digits or 38
  places, or an `exp` past 38 digits, is overflow, a defect. An `exp` so
  far below 0 that it is under half of 10^-18 gives 0, or, with `up`,
  which rounds away from zero, one unit of the last place.
- **The same digits on every target.** The maths works on `Decimal`, as
  there is no `Float`
  ([Representation types](built-in-types.md#representation-types)).
  Jadpo's own decimal code rounds each result correctly to `scale` with
  the named rounding, so it is the same wherever the program runs.
- **In SQL,** PostgreSQL's `round` ties away from zero, which is
  `half_up`. The other modes are spelled out with a `CASE`, never left to
  the database.

A bakery's counts, weights and prices, rounded and compared:

```jadpo
type Portions = Int {
    min: 0
}

type TrayCount = Int {
    min: 1
    max: 12
}

type LoafCount = Int {}

type FlourWeight = Mass {
    min: 0g
}

type Hydration = Decimal {
    scale: 3
    min: 0.000
}

type LoafPrice = Decimal {
    scale: 2
    min: 0.00
}

/// How far a counted batch is from its recipe, either way. `abs` is never
/// below 0, so building `Portions` from it needs no arm.
function drift(in_batch: Portions, recipe: Portions) -> Portions {
    return Portions(integer.abs(in_batch - recipe))
}

/// The trays to bake: what was ordered, but never more than the oven
/// holds. `min` gives one of its two values as it is, still a `TrayCount`.
function trays_to_bake(requested: TrayCount, oven: TrayCount) -> TrayCount {
    return integer.min(requested, oven)
}

/// Whole loaves a sack of flour makes at 450g each: part of a loaf isn't
/// one, so the count rounds down, toward zero. Dividing a weight by a weight
/// gives a plain `Decimal`.
function loaves_from(flour: FlourWeight) -> LoafCount {
    return LoafCount(integer.from_decimal(flour / 450g, rounding: Rounding.down))
}

/// A loaf's price at a fifth off, never below the lowest price.
function sale_price(price: LoafPrice, lowest: LoafPrice) -> LoafPrice {
    return decimal.max(LoafPrice(price * 0.80), lowest)
}

/// A dough's hydration to one place, for its label.
function label_hydration(hydration: Hydration) -> Hydration {
    return Hydration(decimal.round(hydration, scale: 1, rounding: Rounding.half_up))
}

/// The price as a customer reads it, in their own locale.
function price_label(price: LoafPrice, customer: Locale) -> PresentationText {
    return text.format(price, locale: customer)
}
```

A literal passed to `min` or `max` takes the other value's type and is
checked against it, so `integer.min(requested, 20)` is an error, because
`TrayCount` stops at 12. A plain number, such as `requested + 1`, makes
the result a plain `Int`. The tests check these functions, and each
rounding mode to one place:

```jadpo
test "number operations give what the page says" {
    assert drift(980, 1000) == 20
    assert drift(1020, 1000) == 20
    assert trays_to_bake(10, 8) == 8
    assert trays_to_bake(3, 8) == 3
    assert loaves_from(10kg) == 22
    assert loaves_from(449g) == 0
    assert sale_price(4.20, 3.50) == 3.50
    assert sale_price(5.00, 3.50) == 4.00
    assert label_hydration(1.250) == 1.3
    assert label_hydration(1.249) == 1.2
    assert integer.max(3, 8) == 8
    assert decimal.abs(-2.50) == 2.50
    assert decimal.min(4.20, 3.80) == 3.80
    assert price_label(1234.50, Locale.en_gb) == "1,234.50"
    assert price_label(1234.50, Locale.de_de) == "1.234,50"
}

test "every rounding mode, to one place" {
    assert decimal.round(2.25, scale: 1, rounding: Rounding.half_even) == 2.2
    assert decimal.round(2.35, scale: 1, rounding: Rounding.half_even) == 2.4
    assert decimal.round(2.25, scale: 1, rounding: Rounding.half_up) == 2.3
    assert decimal.round(-2.25, scale: 1, rounding: Rounding.half_up) == -2.3
    assert decimal.round(2.21, scale: 1, rounding: Rounding.up) == 2.3
    assert decimal.round(-2.21, scale: 1, rounding: Rounding.up) == -2.3
    assert decimal.round(2.29, scale: 1, rounding: Rounding.down) == 2.2
    assert decimal.round(-2.29, scale: 1, rounding: Rounding.down) == -2.2
    assert integer.from_decimal(2.5, rounding: Rounding.half_even) == 2
    assert integer.from_decimal(-2.5, rounding: Rounding.half_up) == -3
    assert integer.divide(7, 2, rounding: Rounding.down) == 3
}
```

A `scale:` that isn't a whole number from 0 to 18 written out at the
call, as a type's `scale` is, is `type.mismatch`, and one below 0 is
`type.argument_negative` ([Errors](standard-library.md#errors)).

The maths operations, from `sqrt` to `pi`, on the bakery's tins,
starters and deliveries. Each result is the true value rounded to
`scale` places by the mode named, so the same call gives the same digits
on every target:

```jadpo
type Centimetres = Decimal {
    scale: 2
    min: 0.00
}

type SquareCentimetres = Decimal {
    scale: 2
    min: 0.00
}

type Tier = Int {
    min: 0
    max: 6
}

type RecipeScale = Decimal {
    scale: 4
}

type Growth = Decimal {
    scale: 4
    min: 0.0000
}

type Rise = Decimal {
    scale: 6
}

type ProvingTime = Decimal {
    scale: 1
    min: 0.0
}

type Metres = Decimal {
    scale: 1
}

type Course = Decimal {
    scale: 6
}

type NeverRose = Failure {
    kind: FailureKind.invalid_value
}

/// The surface of a round tin, π r².
function tin_area(radius: Centimetres) -> SquareCentimetres {
    return SquareCentimetres(decimal.pi(scale: 6, rounding: Rounding.half_even) * radius * radius)
}

/// The side of a square tin the same size, rounded down so the cake
/// fits. A size is never negative, so its square root needs no check.
function square_side(surface: SquareCentimetres) -> Centimetres {
    return Centimetres(decimal.sqrt(surface, scale: 2, rounding: Rounding.down))
}

/// How much more each tier below the surface needs, at half again a tier:
/// exact, as `1.5 * 1.5 * 1.5` is.
function tier_scale(tier: Tier) -> RecipeScale {
    return RecipeScale(decimal.power(1.5, tier))
}

/// How much a starter grows over `proving`, rising all the while by
/// `rise` an hour. `e` to any power is never below 0, so `Growth` needs no arm.
function risen(rise: Rise, proving: ProvingTime) -> Growth {
    return Growth(decimal.exp(rise * proving, scale: 4, rounding: Rounding.half_even))
}

/// How fast a starter rose an hour, from how much bigger it had `grown`
/// in a day. Growth of 0 has no logarithm: a starter that shrank to
/// nothing never rose.
function hourly_rise(grown: Growth) fails NeverRose -> Rise {
    var daily: Decimal = attempt decimal.ln(grown, scale: 6, rounding: Rounding.half_even) {
        out_of_range: NeverRose
    }
    return Rise(daily / 24.0)
}

/// The direction of a customer at `northing` and `easting` from the
/// bakery, in radians clockwise from north.
function course(northing: Metres, easting: Metres) -> Course {
    return Course(decimal.atan2(easting, northing, scale: 6, rounding: Rounding.half_even))
}

/// Where a van is, east and north of the bakery, `driven` metres on
/// `course`.
function easting_after(driven: Metres, course: Course) -> Metres {
    return Metres(driven * decimal.sin(course, scale: 6, rounding: Rounding.half_even))
}

function northing_after(driven: Metres, course: Course) -> Metres {
    return Metres(driven * decimal.cos(course, scale: 6, rounding: Rounding.half_even))
}
```

`sqrt`'s value and `power`'s exponent must be proved never negative, as
a count is, or the call is `type.argument_negative`. `ln` fails with
`out_of_range` unless its value is proved above 0, by a literal above 0
or a type whose `min` is above 0. `Growth` allows 0, so `hourly_rise`
maps the failure. A result past 38 digits, such as
`decimal.exp(100.0, ...)`, is a defect, as overflow is for `*`. The tests
check these functions, and each mode on the true value:

```jadpo
test "the maths gives what the page says" {
    assert tin_area(10.00) == 314.16
    assert square_side(314.16) == 17.72
    assert tier_scale(3) == 3.375
    assert tier_scale(0) == 1.0
    assert risen(0.100000, 6.0) == 1.8221
    var rise: Rise = attempt hourly_rise(2.0000)
    assert rise == 0.028881
    assert hourly_rise(0.0000) fails NeverRose
    assert course(100.0, 100.0) == 0.785398
    assert course(-100.0, 0.0) == 3.141593
    assert easting_after(1000.0, 0.523599) == 500.0
    assert northing_after(1000.0, 0.523599) == 866.0
}

test "each mode rounds the true value" {
    assert decimal.sqrt(2.0, scale: 3, rounding: Rounding.down) == 1.414
    assert decimal.sqrt(2.0, scale: 3, rounding: Rounding.up) == 1.415
    assert decimal.pi(scale: 4, rounding: Rounding.half_even) == 3.1416
    assert decimal.pi(scale: 4, rounding: Rounding.down) == 3.1415
    assert decimal.exp(1.0, scale: 5, rounding: Rounding.half_up) == 2.71828
    assert decimal.ln(10.0, scale: 5, rounding: Rounding.up) == 2.30259
}
```
