> ## Documentation Index
> Fetch the complete documentation index at: https://docs.canary.effectiveai.app/llms.txt
> Use this file to discover all available pages before exploring further.

# Round a premium

> Round a value the way the filing says, choose the rounding mode, cite the rounding rule, and round after each factor in a chain.

[Install Relativities](https://docs.canary.effectiveai.app/relativities/setup.md) before running the synthetic examples.

This page rounds values with `round(x, places, mode)`. RSL keeps every value exact until a
`round` changes it. So the premium rounds exactly where the filing says, and only there.

## Round to cents or dollars

`round` takes three parts: the value, the number of decimal places, and the mode.
The dwelling-fire rater from [Write your first rater](https://docs.canary.effectiveai.app/rsl/tutorial/first-rater.md) rounds each item charge to cents:

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
charge: Premium [cite: manual:p6] = round(self.value * 0.015, 2, half_up)
```

* `2` rounds to cents, `0` to whole dollars, and `-1` to tens of dollars.
* The mode is required. Write the mode the filing states.
* A value already on the target, such as 2.10 rounded to cents, stays the same in every mode.

## Choose the mode

| Mode | Rounds |
| - | - |
| `half_up` | to the nearest; a half goes away from zero |
| `half_down` | to the nearest; a half goes toward zero |
| `half_even` | to the nearest; a half goes to the even digit |
| `up` | away from zero |
| `down` | toward zero |
| `ceiling` | up, toward the larger number |
| `floor` | down, toward the smaller number |

Save this rater as `round-modes/rater.rsl`. It rounds one amount to cents in four of the modes:

> [accordion] Complete example: round-modes/rater.rsl
>
> ```rsl round-modes/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Guide example",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Records = {
>     Policy = {
>         inputs {
>             amount: Num {precision: 0.001} where self in [-1000, 1000]
>         },
>         half_up: Premium [cite: manual:p9] = round(self.amount, 2, half_up),
>         half_even: Num [cite: manual:p9] = round(self.amount, 2, half_even),
>         ceiling: Num [cite: manual:p9] = round(self.amount, 2, ceiling),
>         floor: Num [cite: manual:p9] = round(self.amount, 2, floor)
>     }
> }
>
> RatingOutcomes = {
>     half_up: Policy.half_up,
>     half_even: Policy.half_even,
>     ceiling: Policy.ceiling,
>     floor: Policy.floor
> }
> ```

Each `round` cites the filed rounding rule, and each rounded value is a rating outcome.
Rate 2.125, -2.125 and 2.121:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
from relativities import Rater

rater = Rater.build("round-modes/rater.rsl")
result = rater.rate([{"amount": 2.125}, {"amount": -2.125}, {"amount": 2.121}])
print(result.to_pandas()[["half_up", "half_even", "ceiling", "floor"]])
#   half_up half_even ceiling  floor
# 0    2.13      2.12    2.13   2.12
# 1   -2.13     -2.12   -2.12  -2.13
# 2    2.12      2.12    2.13   2.12
```

The modes differ on a half, such as 2.125, and on negative amounts.

## Round the premium and cite the rule

Each returned premium needs an explicit rounding operation with a citation on the calculation that performs it.

Use `round(value, places, mode)` and cite the filing’s rounding rule on that calculation.
`E-OUTCOME-ROUND` identifies a missing premium-rounding operation or citation.

## Apply a minimum premium

Wrap the rounded premium in `max` with the filed minimum. Save this rater as `minimum/rater.rsl`:

> [accordion] Complete example: minimum/rater.rsl
>
> ```rsl minimum/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4.1",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Guide example",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Constants = {
>     rate_per_1000 [cite: manual:p3] = 2.15,
>     minimum_premium [cite: manual:p11] = 250
> }
>
> Records = {
>     Policy = {
>         inputs {
>             payroll: Num {precision: int} where self in [0, 100000000]
>         },
>         premium: Premium [cite: manual:p11] =
>             max(round(self.payroll / 1000 * rate_per_1000, 0, half_up), minimum_premium)
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

```rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
premium: Premium [cite: manual:p11] =
    max(round(self.payroll / 1000 * rate_per_1000, 0, half_up), minimum_premium)
```

Rate one payroll on each side of the minimum of 250:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rater = Rater.build("minimum/rater.rsl")
result = rater.rate([{"payroll": 100000}, {"payroll": 150000}])
print(result.to_pandas()[["status", "premium"]])
#       status premium
# 0  succeeded     250
# 1  succeeded     323
```

A payroll of 100,000 rates 215, so the policy pays the minimum. A payroll of 150,000 rates 322.50, which rounds to 323.

* A `max` or `min` of rounded values and constants counts as rounded, so this premium passes the outcome-rounding rule.
* `round(max(x, minimum_premium), 0, half_up)` passes too. Write the order the filing states.
* A `max` over an exact value, such as `max(x, minimum_premium)` alone, gets `E-OUTCOME-ROUND`.
* `min` caps a premium at a filed maximum in the same way.

## Round after each factor

Some filings multiply a chain of factors and round after each one. Save this rater as
`round-stepwise/rater.rsl`:

> [accordion] Complete example: round-stepwise/rater.rsl
>
> ```rsl round-stepwise/rater.rsl theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
> spec {
>     rsl: "0.4",
>     carrier: "Example Mutual",
>     state: AZ,
>     product: "Guide example",
>     effective_date: 2026-01-01
> }
>
> Sources = {
>     manual: Source = {
>         artifact: artifact("00000000-0000-4000-8000-000000000000"),
>         kind: pdf
>     }
> }
>
> Records = {
>     Policy = {
>         inputs {
>             base: Num {precision: 0.01} where self in [100, 10000],
>             factors: List(Adjustment) keyed by order
>         },
>         combined: Factor [cite: manual:p10] =
>             product(self.factors as f by f.order, f.value, round_each: (4, half_up)),
>         premium: Premium [cite: manual:p10] = round(self.base * self.combined, 2, half_up)
>     },
>     Adjustment = {
>         inputs {
>             order: Num {precision: int} where self in [1, 20],
>             value: Num {precision: 0.00001} where self in [0.5, 2]
>         }
>     }
> }
>
> RatingOutcomes = {
>     premium: Policy.premium
> }
> ```

The `combined` calculation writes a `product` with `by`, to fix the order, and `round_each`.
The rater sorts the factors by `order`, multiplies them in turn, and rounds to 4 places after each
step. Two factors of 1.00005 give 1.0002. One round at the end gives 1.0001:

```python theme={"languages":{"custom":["languages/rsl.tmLanguage.json"]}}
rater = Rater.build("round-stepwise/rater.rsl")
policy = {"base": 500, "factors": [{"order": 1, "value": 1.00005}, {"order": 2, "value": 1.00005}]}
print(rater.explain(policy))
#           kind              name    value
# 0        input              base      500
# 1        input  factors[0].order        1
# 2        input  factors[0].value  1.00005
# 3        input  factors[1].order        2
# 4        input  factors[1].value  1.00005
# 5  calculation          combined   1.0002
# 6  calculation           premium    500.1
```

`explain` lists each input, then each calculation in order, with its exact value.

* `by` names a number or date input of each element.
* Each `order` value appears once. The rater refuses a repeat with `INPUT-KEY` on a `keyed by` list, and with `INPUT-UNIQUE` on other lists.
* `round_each` works with `sum` and `product`.

## Related

* [Exact numbers](https://docs.canary.effectiveai.app/rsl/explanation/exact-numbers.md) explains why values stay exact until a `round`.
* [Citations](https://docs.canary.effectiveai.app/rsl/explanation/citations.md) lists each value that needs a citation.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.