Case 984
The taller tyres made every kilometre read short
the_taller_tyres_made_every_kilometre_read_short.eml - A driver replaces 205/55 R16 tyres with taller 225/60 R16 ones on the same rims, keeps the needle at the 100 km/h limit on the motorway, and reasons that the speedometer shows the car's speed and reads a little high anyway. What the needle means on the new tyres is computed below.
ok: true — round-trip fixpoint reached (python1 == python2)updated 2026-09-23
EML
eml# Self-authored for the EML case corpus (no external origin). A driver replaces
# 205/55 R16 tyres with taller 225/60 R16 ones on the same rims, keeps the
# needle at the 100 km/h limit on the motorway, and reasons that the
# speedometer shows the car's speed and reads a little high anyway. What the
# needle means on the new tyres is computed below.
#
# The reasoning is careful. The needle really does sit at 100; nothing in the
# car's electronics was changed; the speedometer really did read high before,
# 100 on the needle at a true 96; and the intent is exactly 'stay at the limit'.
#
# A speedometer does not see the road; it counts turns of the wheels and was
# calibrated for the old tyre's circumference. The taller tyre covers 10704 per
# ten thousand of the old distance in each turn, so the needle's 100 is now a
# true 102: the factory's four-kilometre margin has become two over. The
# odometer, accurate before, now shows 18684 of every 20000 km driven.
16 => rim_inches
254 => tenths_of_a_mm_per_inch
205 => old_tyre_width_mm
55 => old_sidewall_percent
225 => new_tyre_width_mm
60 => new_sidewall_percent
100 => indicated_kmh
96 => true_kmh_at_the_needle_100_on_the_old_tyres
20000 => km_driven_in_a_year
rim_inches * tenths_of_a_mm_per_inch => rim_tenths_of_a_mm
rim_tenths_of_a_mm + int(2 * old_tyre_width_mm * old_sidewall_percent * 10 / 100) => old_diameter_tenths_of_a_mm
rim_tenths_of_a_mm + int(2 * new_tyre_width_mm * new_sidewall_percent * 10 / 100) => new_diameter_tenths_of_a_mm
int(new_diameter_tenths_of_a_mm * 10000 / old_diameter_tenths_of_a_mm) => road_per_turn_vs_old_per_myriad
int(true_kmh_at_the_needle_100_on_the_old_tyres * new_diameter_tenths_of_a_mm / old_diameter_tenths_of_a_mm) => true_kmh_at_the_needle_100_now
indicated_kmh - true_kmh_at_the_needle_100_on_the_old_tyres => old_margin_kmh
true_kmh_at_the_needle_100_now - indicated_kmh => now_over_the_needle_kmh
int(km_driven_in_a_year * old_diameter_tenths_of_a_mm / new_diameter_tenths_of_a_mm) => odometer_shows_km
km_driven_in_a_year - odometer_shows_km => odometer_short_by_km
"rim : " + str(rim_inches) + " inches, " + str(rim_tenths_of_a_mm) + " tenths of a mm" ^0
"old tyre, 205/55 : " + str(old_diameter_tenths_of_a_mm) + " tenths of a mm across" ^0
"new tyre, 225/60 : " + str(new_diameter_tenths_of_a_mm) + " tenths of a mm across" ^0
"road per wheel turn vs old : " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand" ^0
"" ^0
"needle at " + str(indicated_kmh) + ", old tyres : true " + str(true_kmh_at_the_needle_100_on_the_old_tyres) + " km/h, " + str(old_margin_kmh) + " under the needle" ^0
"needle at " + str(indicated_kmh) + ", new tyres : true " + str(true_kmh_at_the_needle_100_now) + " km/h, " + str(now_over_the_needle_kmh) + " over the needle" ^0
"odometer after " + str(km_driven_in_a_year) + " km driven : " + str(odometer_shows_km) + " km, short by " + str(odometer_short_by_km) ^0
"" ^0
# ---- what the driver verified ----
"the needle-is-the-speed reasoning" ^0
" needle : exactly at " + str(indicated_kmh) ^0
" electronics : unchanged" ^0
" known margin : the needle read " + str(old_margin_kmh) + " high on the old tyres" ^0
" intent : stay at the limit" ^0
" facts wrong : 0" ^0
" verdict : AT 100 ON THE NEEDLE I AM AT OR UNDER THE LIMIT" ^0
"" ^0
" holding the needle exactly at " + str(indicated_kmh) + " is the part done right here," ^0
" and it is why the wheels turn at exactly the rate that" ^0
" meant " + str(true_kmh_at_the_needle_100_on_the_old_tyres) + " km/h on the old tyres" ^0
"" ^0
# ---- what the needle counts ----
"a speedometer counts turns" ^0
" what it measures : how fast the wheels turn" ^0
" what it assumes : how much road one turn covers, the old" ^0
" tyre's circumference" ^0
" the new tyre : " + str(new_diameter_tenths_of_a_mm) + " tenths of a mm across instead of " + str(old_diameter_tenths_of_a_mm) + "," ^0
" so each turn covers " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand of the old distance" ^0
" the same turning rate : now a true " + str(true_kmh_at_the_needle_100_now) + " km/h; the margin" ^0
" of " + str(old_margin_kmh) + " under has become " + str(now_over_the_needle_kmh) + " over" ^0
" the odometer : counts the same turns, and loses " + str(odometer_short_by_km) + " km a year" ^0
"" ^0
# ---- what the driver got ----
"the motorway" ^0
" believed : at or under the limit, with room to spare" ^0
" actual : " + str(true_kmh_at_the_needle_100_now) + " km/h at a needle of " + str(indicated_kmh) ^0
" is the speedometer broken : no; it counts turns exactly as before" ^0
" does the needle show the car's speed : only for the tyre it" ^0
" was calibrated on" ^0
"" ^0
# ---- null control ----
# The same needle recalibrated for the new tyre's circumference instead of left
# on the old one.
102 => nc_true_kmh_at_the_needle_100_uncalibrated
96 => nc_true_kmh_at_the_needle_100_recalibrated
6 => nc_kmh_the_recalibration_returns
"null control - recalibrate for the new tyre" ^0
" true speed at a needle of 100, uncalibrated : " + str(nc_true_kmh_at_the_needle_100_uncalibrated) + " km/h" ^0
" true speed at a needle of 100, recalibrated : " + str(nc_true_kmh_at_the_needle_100_recalibrated) + " km/h" ^0
" km/h the recalibration returns : " + str(nc_kmh_the_recalibration_returns) ^0
" no tyre and no road changed; the instrument was told how much" ^0
" road one turn now covers" ^0
"" ^0
# ---- the rule ----
"what an unchanged speedometer guarantees" ^0
" it counts wheel turns exactly as before : exactly" ^0
" its needle shows the car's speed : not addressed; a turn of the" ^0
" taller tyre covers " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand of the old distance," ^0
" so the needle's " + str(indicated_kmh) + " is a true " + str(true_kmh_at_the_needle_100_now) + " and the year's " + str(km_driven_in_a_year) + " km" ^0
" show as " + str(odometer_shows_km) ^0
"" ^0
"an instrument that counts something else and converts is only as right as" ^0
"its conversion; change what one count is worth and every reading drifts by" ^0
"the same share, silently" ^0
"" ^0
"The needle sits at " + str(indicated_kmh) + " and the electronics are untouched - both true. But the" ^0
"speedometer counts turns, and a turn of the taller tyre covers " + str(road_per_turn_vs_old_per_myriad) + " per ten" ^0
"thousand of the old one's road, so the needle's " + str(indicated_kmh) + " is a true " + str(true_kmh_at_the_needle_100_now) + " and " + str(km_driven_in_a_year) + " km" ^0
"read as " + str(odometer_shows_km) + ", until the speedometer is told what one turn is now worth." ^0Python (deterministic transpilation)
pythonrim_inches = 16
tenths_of_a_mm_per_inch = 254
old_tyre_width_mm = 205
old_sidewall_percent = 55
new_tyre_width_mm = 225
new_sidewall_percent = 60
indicated_kmh = 100
true_kmh_at_the_needle_100_on_the_old_tyres = 96
km_driven_in_a_year = 20000
rim_tenths_of_a_mm = rim_inches * tenths_of_a_mm_per_inch
old_diameter_tenths_of_a_mm = rim_tenths_of_a_mm + int(2 * old_tyre_width_mm * old_sidewall_percent * 10 / 100)
new_diameter_tenths_of_a_mm = rim_tenths_of_a_mm + int(2 * new_tyre_width_mm * new_sidewall_percent * 10 / 100)
road_per_turn_vs_old_per_myriad = int(new_diameter_tenths_of_a_mm * 10000 / old_diameter_tenths_of_a_mm)
true_kmh_at_the_needle_100_now = int(true_kmh_at_the_needle_100_on_the_old_tyres * new_diameter_tenths_of_a_mm / old_diameter_tenths_of_a_mm)
old_margin_kmh = indicated_kmh - true_kmh_at_the_needle_100_on_the_old_tyres
now_over_the_needle_kmh = true_kmh_at_the_needle_100_now - indicated_kmh
odometer_shows_km = int(km_driven_in_a_year * old_diameter_tenths_of_a_mm / new_diameter_tenths_of_a_mm)
odometer_short_by_km = km_driven_in_a_year - odometer_shows_km
print("rim : " + str(rim_inches) + " inches, " + str(rim_tenths_of_a_mm) + " tenths of a mm")
print("old tyre, 205/55 : " + str(old_diameter_tenths_of_a_mm) + " tenths of a mm across")
print("new tyre, 225/60 : " + str(new_diameter_tenths_of_a_mm) + " tenths of a mm across")
print("road per wheel turn vs old : " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand")
print("")
print("needle at " + str(indicated_kmh) + ", old tyres : true " + str(true_kmh_at_the_needle_100_on_the_old_tyres) + " km/h, " + str(old_margin_kmh) + " under the needle")
print("needle at " + str(indicated_kmh) + ", new tyres : true " + str(true_kmh_at_the_needle_100_now) + " km/h, " + str(now_over_the_needle_kmh) + " over the needle")
print("odometer after " + str(km_driven_in_a_year) + " km driven : " + str(odometer_shows_km) + " km, short by " + str(odometer_short_by_km))
print("")
print("the needle-is-the-speed reasoning")
print(" needle : exactly at " + str(indicated_kmh))
print(" electronics : unchanged")
print(" known margin : the needle read " + str(old_margin_kmh) + " high on the old tyres")
print(" intent : stay at the limit")
print(" facts wrong : 0")
print(" verdict : AT 100 ON THE NEEDLE I AM AT OR UNDER THE LIMIT")
print("")
print(" holding the needle exactly at " + str(indicated_kmh) + " is the part done right here,")
print(" and it is why the wheels turn at exactly the rate that")
print(" meant " + str(true_kmh_at_the_needle_100_on_the_old_tyres) + " km/h on the old tyres")
print("")
print("a speedometer counts turns")
print(" what it measures : how fast the wheels turn")
print(" what it assumes : how much road one turn covers, the old")
print(" tyre's circumference")
print(" the new tyre : " + str(new_diameter_tenths_of_a_mm) + " tenths of a mm across instead of " + str(old_diameter_tenths_of_a_mm) + ",")
print(" so each turn covers " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand of the old distance")
print(" the same turning rate : now a true " + str(true_kmh_at_the_needle_100_now) + " km/h; the margin")
print(" of " + str(old_margin_kmh) + " under has become " + str(now_over_the_needle_kmh) + " over")
print(" the odometer : counts the same turns, and loses " + str(odometer_short_by_km) + " km a year")
print("")
print("the motorway")
print(" believed : at or under the limit, with room to spare")
print(" actual : " + str(true_kmh_at_the_needle_100_now) + " km/h at a needle of " + str(indicated_kmh))
print(" is the speedometer broken : no; it counts turns exactly as before")
print(" does the needle show the car's speed : only for the tyre it")
print(" was calibrated on")
print("")
nc_true_kmh_at_the_needle_100_uncalibrated = 102
nc_true_kmh_at_the_needle_100_recalibrated = 96
nc_kmh_the_recalibration_returns = 6
print("null control - recalibrate for the new tyre")
print(" true speed at a needle of 100, uncalibrated : " + str(nc_true_kmh_at_the_needle_100_uncalibrated) + " km/h")
print(" true speed at a needle of 100, recalibrated : " + str(nc_true_kmh_at_the_needle_100_recalibrated) + " km/h")
print(" km/h the recalibration returns : " + str(nc_kmh_the_recalibration_returns))
print(" no tyre and no road changed; the instrument was told how much")
print(" road one turn now covers")
print("")
print("what an unchanged speedometer guarantees")
print(" it counts wheel turns exactly as before : exactly")
print(" its needle shows the car's speed : not addressed; a turn of the")
print(" taller tyre covers " + str(road_per_turn_vs_old_per_myriad) + " per ten thousand of the old distance,")
print(" so the needle's " + str(indicated_kmh) + " is a true " + str(true_kmh_at_the_needle_100_now) + " and the year's " + str(km_driven_in_a_year) + " km")
print(" show as " + str(odometer_shows_km))
print("")
print("an instrument that counts something else and converts is only as right as")
print("its conversion; change what one count is worth and every reading drifts by")
print("the same share, silently")
print("")
print("The needle sits at " + str(indicated_kmh) + " and the electronics are untouched - both true. But the")
print("speedometer counts turns, and a turn of the taller tyre covers " + str(road_per_turn_vs_old_per_myriad) + " per ten")
print("thousand of the old one's road, so the needle's " + str(indicated_kmh) + " is a true " + str(true_kmh_at_the_needle_100_now) + " and " + str(km_driven_in_a_year) + " km")
print("read as " + str(odometer_shows_km) + ", until the speedometer is told what one turn is now worth.")stdout (executed)
textrim : 16 inches, 4064 tenths of a mm
old tyre, 205/55 : 6319 tenths of a mm across
new tyre, 225/60 : 6764 tenths of a mm across
road per wheel turn vs old : 10704 per ten thousand
needle at 100, old tyres : true 96 km/h, 4 under the needle
needle at 100, new tyres : true 102 km/h, 2 over the needle
odometer after 20000 km driven : 18684 km, short by 1316
the needle-is-the-speed reasoning
needle : exactly at 100
electronics : unchanged
known margin : the needle read 4 high on the old tyres
intent : stay at the limit
facts wrong : 0
verdict : AT 100 ON THE NEEDLE I AM AT OR UNDER THE LIMIT
holding the needle exactly at 100 is the part done right here,
and it is why the wheels turn at exactly the rate that
meant 96 km/h on the old tyres
a speedometer counts turns
what it measures : how fast the wheels turn
what it assumes : how much road one turn covers, the old
tyre's circumference
the new tyre : 6764 tenths of a mm across instead of 6319,
so each turn covers 10704 per ten thousand of the old distance
the same turning rate : now a true 102 km/h; the margin
of 4 under has become 2 over
the odometer : counts the same turns, and loses 1316 km a year
the motorway
believed : at or under the limit, with room to spare
actual : 102 km/h at a needle of 100
is the speedometer broken : no; it counts turns exactly as before
does the needle show the car's speed : only for the tyre it
was calibrated on
null control - recalibrate for the new tyre
true speed at a needle of 100, uncalibrated : 102 km/h
true speed at a needle of 100, recalibrated : 96 km/h
km/h the recalibration returns : 6
no tyre and no road changed; the instrument was told how much
road one turn now covers
what an unchanged speedometer guarantees
it counts wheel turns exactly as before : exactly
its needle shows the car's speed : not addressed; a turn of the
taller tyre covers 10704 per ten thousand of the old distance,
so the needle's 100 is a true 102 and the year's 20000 km
show as 18684
an instrument that counts something else and converts is only as right as
its conversion; change what one count is worth and every reading drifts by
the same share, silently
The needle sits at 100 and the electronics are untouched - both true. But the
speedometer counts turns, and a turn of the taller tyre covers 10704 per ten
thousand of the old one's road, so the needle's 100 is a true 102 and 20000 km
read as 18684, until the speedometer is told what one turn is now worth.Trace event types
eml:run:starteml:assigneml:outputeml:run:done