Case 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.
ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-07-29
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))^0Python (deterministic transpilation)
pythonitems = [["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)
textITEM 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]Trace event types
eml:run:starteml:assigneml:outputeml:run:done