<!-- canonical: efficientnewlanguage.org/ai/examples/147-receipt-formatter | ai_layer_version: 0.1.0 | updated: 2026-07-29 -->

# Example 147 — A receipt, and what `%` rounding actually does

`receipt_formatter.eml` is the smallest honest excuse to use every part of `%`-formatting at once: left-aligned names, right-aligned integers, fixed two-decimal money, and a percentage.

## EML

```eml
# Self-authored for the EML case corpus (no external origin). A receipt, which
# is the smallest honest excuse to use every part of %-formatting at once:
# left-aligned names, right-aligned integers, fixed two-decimal money, and a
# percentage.
#
# This case could not have been written last week. EML's interpreter supported
# only bare %s, %d and %f - the moment a program asked for %.2f, %5d or %-12s
# it raised `ValueError: unsupported format character` in the browser while the
# transpiled Python printed the right thing. Since %.2f is simply how you write
# money, that made most real formatting a divergence rather than a feature.
#
# The interesting part of the fix, and the reason a case pins it: rounding.
# %-formatting rounds the EXACT binary value, ties to even. Both halves of that
# matter and both are visible below:
#
#   1.005 prints as 1.00, not 1.01, because the double nearest 1.005 is
#   actually 1.00499999999999989..., so it is not a tie at all and rounds down.
#
#   0.125 prints as 0.12, not 0.13, because 0.125 IS exactly representable, so
#   it is a real tie, and ties go to the even digit.
#
# Those two lines look inconsistent and are not. Any implementation that
# rounds the decimal you typed rather than the double you got will disagree
# with Python on the first; any implementation that rounds ties away from zero
# will disagree on the second.

items^+[["Coffee beans 1kg", 2, 18.5],
        ["Filter papers", 1, 3.25],
        ["Mug", 3, 7.0],
        ["Gift card", 1, 25.0]]

"%-20s %3s %8s %9s" % ("ITEM", "QTY", "PRICE", "TOTAL") => header
header^0
("-" * 42)^0

0.0 => subtotal
0 => units
for row in items:
    row[0] => name
    row[1] => qty
    row[2] => price
    qty * price => line_total
    subtotal + line_total => subtotal
    units + qty => units
    ("%-20s %3d %8.2f %9.2f" % (name, qty, price, line_total))^0

("-" * 42)^0
0.08 => tax_rate
subtotal * tax_rate => tax
subtotal + tax => grand

("%-20s %3d %8s %9.2f" % ("subtotal", units, "", subtotal))^0
("%-20s %3s %7.1f%% %9.2f" % ("tax", "", tax_rate * 100, tax))^0
("%-20s %3s %8s %9.2f" % ("TOTAL", "", "", grand))^0

""^0
"Rounding, where %-formatting earns its keep:" => h2
h2^0
("  1.005 -> %.2f   (the double is 1.00499999..., so it rounds DOWN)" % (1.005,))^0
("  0.125 -> %.2f   (exactly representable, a true tie, so it goes to EVEN)" % (0.125,))^0
("  2.675 -> %.2f   (again below the decimal you typed)" % (2.675,))^0
("  2.5   -> %.0f     and 3.5 -> %.0f   (both to the even neighbour)" % (2.5, 3.5))^0

""^0
"Padding and sign flags:" => h3
h3^0
("  [%8.2f] [%-8.2f] [%+.2f] [%08.2f]" % (grand, grand, grand, grand))^0
("  [%5d] [%-5d] [%05d] [%x] [%o]" % (units, units, units, 255, 8))^0
```

## Python (deterministic transpilation)

```python
items = [["Coffee beans 1kg", 2, 18.5], ["Filter papers", 1, 3.25], ["Mug", 3, 7.0], ["Gift card", 1, 25.0]]
header = "%-20s %3s %8s %9s" % ("ITEM", "QTY", "PRICE", "TOTAL")
print(header)
print("-" * 42)
subtotal = 0.0
units = 0
for row in items:
    name = row[0]
    qty = row[1]
    price = row[2]
    line_total = qty * price
    subtotal = subtotal + line_total
    units = units + qty
    print("%-20s %3d %8.2f %9.2f" % (name, qty, price, line_total))
print("-" * 42)
tax_rate = 0.08
tax = subtotal * tax_rate
grand = subtotal + tax
print("%-20s %3d %8s %9.2f" % ("subtotal", units, "", subtotal))
print("%-20s %3s %7.1f%% %9.2f" % ("tax", "", tax_rate * 100, tax))
print("%-20s %3s %8s %9.2f" % ("TOTAL", "", "", grand))
print("")
h2 = "Rounding, where %-formatting earns its keep:"
print(h2)
print("  1.005 -> %.2f   (the double is 1.00499999..., so it rounds DOWN)" % (1.005,))
print("  0.125 -> %.2f   (exactly representable, a true tie, so it goes to EVEN)" % (0.125,))
print("  2.675 -> %.2f   (again below the decimal you typed)" % (2.675,))
print("  2.5   -> %.0f     and 3.5 -> %.0f   (both to the even neighbour)" % (2.5, 3.5))
print("")
h3 = "Padding and sign flags:"
print(h3)
print("  [%8.2f] [%-8.2f] [%+.2f] [%08.2f]" % (grand, grand, grand, grand))
print("  [%5d] [%-5d] [%05d] [%x] [%o]" % (units, units, units, 255, 8))
```

## stdout (executed)

```text
ITEM                 QTY    PRICE     TOTAL
------------------------------------------
Coffee beans 1kg       2    18.50     37.00
Filter papers          1     3.25      3.25
Mug                    3     7.00     21.00
Gift card              1    25.00     25.00
------------------------------------------
subtotal               7              86.25
tax                          8.0%      6.90
TOTAL                                 93.15

Rounding, where %-formatting earns its keep:
  1.005 -> 1.00   (the double is 1.00499999..., so it rounds DOWN)
  0.125 -> 0.12   (exactly representable, a true tie, so it goes to EVEN)
  2.675 -> 2.67   (again below the decimal you typed)
  2.5   -> 2     and 3.5 -> 4   (both to the even neighbour)

Padding and sign flags:
  [   93.15] [93.15   ] [+93.15] [00093.15]
  [    7] [7    ] [00007] [ff] [10]
```

## Round-trip

`ok: true` — round-trip fixpoint reached (python1 == python2)

## Trace event types

eml:run:start · eml:assign · eml:output · eml:run:done
