docs← Back to article

Markdown for LLMs

Rounding required by the rule

The source Markdown for this article. Copy it into your assistant or download it as a text file.

Download this articlePlain text ↗
# Rounding required by the rule

## Intention

I want to set the scale and rounding mode of a money amount explicitly.

The policy must be explicit: the scenes below check the positive and negative half-steps and the HALF_UP/HALF_EVEN difference.

## Incorrect form and why it stays silent

```text title="Incorrect form"
pure function Pay(x: Money) -> Money = round(x);
```

Rounding has no hidden scale or mode. Trailing zeros on a literal do not set legal precision: the arguments of round do.

## Correct form

```law
language "law.core" version "0.2";
package recipes.l.r03 version "0.1.0";
namespace "urn:recipe:l-calc:03";

pure function Pay(x: Money) -> Money = round(x, 2, "HALF_UP");
```

## Frozen execution scene

| Facts and choice | Question | Answer |
|---|---|---|
| 1. positive half-step | `Pay(1.005 KZT)` | `1.01 KZT` / `COMPUTED` |
| 2. negative half-step | `Pay(-1.005 KZT)` | `-1.01 KZT` / `COMPUTED` |
| 3. banker's rounding of a half | `round(1.005 KZT, 2, "HALF_EVEN")` | `1 KZT` / `COMPUTED` |
| 4. literal zeros do not change the amount | `Pay(1.5000 KZT)` | `1.5 KZT` / `COMPUTED` |

```law
test "positive half step up" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        
    }
    evaluate Pay(1.005 KZT);
    expect value == 1.01 KZT;
    expect evaluation_status == COMPUTED;
    
}
```

```law
test "negative half step" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        
    }
    evaluate Pay(-1.005 KZT);
    expect value == -1.01 KZT;
    expect evaluation_status == COMPUTED;
    
}
```

```law
test "banker's rounding of half" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        
    }
    evaluate round(1.005 KZT, 2, "HALF_EVEN");
    expect value == 1 KZT;
    expect evaluation_status == COMPUTED;
    
}
```

```law
test "literal zeros keep sum" {
    given {
        context {
            legal_time @2026-09-13;
            decision_time @2026-09-13T09:00:00+05:00;
            knowledge_time @2026-09-13T09:00:00+05:00;
            timezone "Asia/Almaty";
        }
        
    }
    evaluate Pay(1.5000 KZT);
    expect value == 1.5 KZT;
    expect evaluation_status == COMPUTED;
    
}
```



## Counterfactual

Mutation: `round(x, 2, "HALF_UP")` → `round(x)`; expected `LDC-E2116`. Additional counterfactuals are shown as separate table rows.

## Boundary

Round at the stage the rule names. For a quotient, first compute it exactly or use div_round — see [Division under an explicit policy](/recipes/l-calc/division-precision/). Canonical value notation may drop trailing zeros; that is not a change of rounding mode.

## Pitfall

Rounding with an unstated scale or mode has no default; the scenes pin both half-steps and both modes.