Fuel economy
Two cars and a round trip: the van gaining 4 km/L saves more fuel than the sedan gaining 20, and 30 out and 60 back averages 40, not 45.
Every screen below was recorded under CPython. When this page was built, the EML interpreter replayed each session from the same input and printed the same bytes.
About
A household's two cars and a round trip, and the scale that adds up.
main.eml- the menu, the cars, which swap saves more, the round trip, a swap of your own and a trip of your ownfuel.eml- the cars, litres a year, litres saved, litres per 100 km, the trip, and the average speed over two equal legs
How each part works:
- Fuel used is distance divided by kilometres per litre; litres are kept in tenths, from exact integer arithmetic rounded once.
- As in the corpus case
the-van-gaining-four-saved-more-than-the-hybrid-gaining-twenty, each car drives 10,000 km a year: the van goes from 8 km/L to 12, the sedan from 20 to 40. A gain of 20 is five times a gain of 4, and the van's swap saves 416.7 litres a year to the hybrid's 250.0: a gain counts most where km/L is lowest. In litres per 100 km, the scale that adds up, the van gains 4.2 and the sedan 2.5. - As in
the-average-speed-was-the-mean-of-the-legs, 60 km out at 30 km/h and back at 60 is 120 km in 3 hours, 40.0 km/h, where the mean of the speeds is 45.0: the slow leg takes longer. The average is never above the mean, and equal only at one speed.
What is checked: menu choices 1 to 6; 1 to 100000 km a year; 1 to 99 km per litre; speeds of 1 to 200 km/h. An empty answer cancels.
Sessions: sessions/basic.in gives: - the cars, the swaps and the round trip; - swaps of your own: 6 to 7 km/L over 15,000 km, and 30 to 25 over 10,000 (more fuel); - trips at 30 and 60, at 100 and 101 (the same to a tenth) and at 50 and 50.
sessions/bad-input.in gives: - menu choices 0 and x; - km a year: a cancel, 0, 100001 and x; km/L: a cancel, 0, 100 and x, twice; then 8 to 8 km/L; - speeds: a cancel, 0, 201 and x, then a cancel and 0 for the way back; - 1 and 200 km/h.
Built on the verified corpus cases the-van-gaining-four-saved-more-than-the-hybrid-gaining-twenty (two cars and which replacement saves more fuel) and the-average-speed-was-the-mean-of-the-legs (30 km/h out, 60 back over the same road).
Recorded sessions
What the screen shows while someone uses the program. Each typed line appears after its prompt, the way a terminal shows it.
bad-input
interpreter: byte-equal== Fuel economy ==
Two cars, a round trip, and the scale that adds up.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 0
Pick a number from 1 to 6.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> x
Pick a number from 1 to 6.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)>
Cancelled.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 0
Type a whole number from 1 to 100000.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100001
Type a whole number from 1 to 100000.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> x
Type a whole number from 1 to 100000.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)>
Cancelled.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 0
Type a whole number from 1 to 99.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 100
Type a whole number from 1 to 99.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> x
Type a whole number from 1 to 99.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 8
km per litre after (1 to 99)>
Cancelled.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 8
km per litre after (1 to 99)> 0
Type a whole number from 1 to 99.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 8
km per litre after (1 to 99)> x
Type a whole number from 1 to 99.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 100
km per litre now (1 to 99)> 8
km per litre after (1 to 99)> 8
At 100 km a year: 12.5 litres now, 12.5 after; 12.5 and 12.5 litres per 100 km.
The swap changes nothing.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)>
Cancelled.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 0
Type a whole number from 1 to 200.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 201
Type a whole number from 1 to 200.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> x
Type a whole number from 1 to 200.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 40
speed back, km/h (1 to 200)>
Cancelled.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 40
speed back, km/h (1 to 200)> 0
Type a whole number from 1 to 200.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 1
speed back, km/h (1 to 200)> 200
Two legs of the same length at 1 and 200 km/h: the mean of the speeds is 100.5, the average speed 2.0.
The average is the lower, always: more of the time is spent on the slower leg.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 6
Bye.
What was typed (56 lines)
0
x
4
4
0
4
100001
4
x
4
100
4
100
0
4
100
100
4
100
x
4
100
8
4
100
8
0
4
100
8
x
4
100
8
8
5
5
0
5
201
5
x
5
40
5
40
0
5
1
200
6
basic
interpreter: byte-equal== Fuel economy ==
Two cars, a round trip, and the scale that adds up.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 1
Two cars, each driven 10,000 km a year; the household can afford to replace one:
van 8 km/L now, 12 with its replacement: a gain of 4 km/L
sedan 20 km/L now, 40 with its replacement: a gain of 20 km/L
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 2
Fuel a year, now and after each swap:
car now after saved L/100 km, now and after
van 1,250.0 L 833.3 L 416.7 L 12.5 and 8.3
sedan 500.0 L 250.0 L 250.0 L 5.0 and 2.5
A gain of 20 km/L is five times a gain of 4, and the van's swap saves 416.7 litres a year to the hybrid's 250.0. Fuel used is distance divided by km/L, so a gain counts most where km/L is lowest; in litres per 100 km the van gains 4.2 and the sedan 2.5.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 3
60 km out at 30 km/h and 60 km back at 60 km/h: 2 hours out and 1 back.
The mean of the two speeds is 45.0 km/h. The trip's average is 120 km in 3 hours, 40.0 km/h: the slow leg takes longer, so it counts for more of the time.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 15000
km per litre now (1 to 99)> 6
km per litre after (1 to 99)> 7
At 15,000 km a year: 2,500.0 litres now, 2,142.9 after; 16.7 and 14.3 litres per 100 km.
The swap saves 357.1 litres a year.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 4
km a year (1 to 100000)> 10000
km per litre now (1 to 99)> 30
km per litre after (1 to 99)> 25
At 10,000 km a year: 333.3 litres now, 400.0 after; 3.3 and 4.0 litres per 100 km.
The swap uses 66.7 litres a year more.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 30
speed back, km/h (1 to 200)> 60
Two legs of the same length at 30 and 60 km/h: the mean of the speeds is 45.0, the average speed 40.0.
The average is the lower, always: more of the time is spent on the slower leg.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 100
speed back, km/h (1 to 200)> 101
Two legs of the same length at 100 and 101 km/h: the mean of the speeds is 100.5, the average speed 100.5.
Rounded to a tenth they look the same; the average is still the lower, as it always is: more of the time is spent on the slower leg.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 5
speed out, km/h (1 to 200)> 50
speed back, km/h (1 to 200)> 50
Two legs of the same length at 50 and 50 km/h: the mean of the speeds is 50.0, the average speed 50.0.
At one speed they are the same.
1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit
choice> 6
Bye.
What was typed (21 lines)
1
2
3
4
15000
6
7
4
10000
30
25
5
30
60
5
100
101
5
50
50
6
Modules
The program as written, entry module first. Each module transpiles to its own Python file, which is what eml project run executes.
main.eml(entry)
eml# P178 fuel economy: two cars and a round trip - the cars, which swap saves
# more fuel, the trip's average speed, a swap of your own and a trip of
# your own.
import fuel
def plain(s):
0 => i
len(s) => j
while i < j and s[i] == " ":
i + 1 => i
while j > i and s[j - 1] == " ":
j - 1 => j
return s[i:j]
def pad(s, n):
s => out
while len(out) < n:
out + " " => out
return out
def lpad(s, n):
s => out
while len(out) < n:
" " + out => out
return out
def digits(t):
for c in t:
if c < "0" or c > "9":
return False
return len(t) > 0
def commas(n):
str(n) => s
"" => out
0 => k
len(s) => i
while i > 0:
if k == 3:
"," + out => out
0 => k
s[i - 1] + out => out
k + 1 => k
i - 1 => i
return out
def t1(t):
# tenths, t >= 0
return commas(int((t - t % 10) / 10)) + "." + str(t % 10)
def show_cars():
"Two cars, each driven 10,000 km a year; the household can afford to replace one:" ^0
for c in fuel.cars():
(" " + pad(c[0], 7) + lpad(str(c[2]), 2) + " km/L now, " + lpad(str(c[3]), 2) + " with its replacement: a gain of " + str(c[3] - c[2]) + " km/L") ^0
def show_swaps():
"Fuel a year, now and after each swap:" ^0
(" " + pad("car", 7) + lpad("now", 10) + lpad("after", 10) + lpad("saved", 10) + " L/100 km, now and after") ^0
[] => s
for c in fuel.cars():
fuel.saved(c[1], c[2], c[3]) => v
s + [v] => s
(" " + pad(c[0], 7) + lpad(t1(fuel.litres(c[1], c[2])) + " L", 10) + lpad(t1(fuel.litres(c[1], c[3])) + " L", 10) + lpad(t1(v) + " L", 10) + " " + t1(fuel.per_100(c[2])) + " and " + t1(fuel.per_100(c[3]))) ^0
("A gain of 20 km/L is five times a gain of 4, and the van's swap saves " + t1(s[0]) + " litres a year to the hybrid's " + t1(s[1]) + ". Fuel used is distance divided by km/L, so a gain counts most where km/L is lowest; in litres per 100 km the van gains " + t1(fuel.tenths_of(100 * 4, 8 * 12)) + " and the sedan " + t1(fuel.tenths_of(100 * 20, 20 * 40)) + ".") ^0
def show_trip():
fuel.trip() => t
(str(t[0]) + " km out at " + str(t[1]) + " km/h and " + str(t[0]) + " km back at " + str(t[2]) + " km/h: " + str(int(t[0] / t[1])) + " hours out and " + str(int(t[0] / t[2])) + " back.") ^0
("The mean of the two speeds is " + t1(fuel.tenths_of(t[1] + t[2], 2)) + " km/h. The trip's average is " + str(2 * t[0]) + " km in " + str(int(t[0] / t[1]) + int(t[0] / t[2])) + " hours, " + t1(fuel.average(t[1], t[2])) + " km/h: the slow leg takes longer, so it counts for more of the time.") ^0
def number(prompt, lo, hi):
plain(input(prompt + " (" + str(lo) + " to " + str(hi) + ")> ")) => t
if t == "":
"Cancelled." ^0
return 0 - 1
if len(t) > len(str(hi)) or not digits(t) or int(t) < lo or int(t) > hi:
("Type a whole number from " + str(lo) + " to " + str(hi) + ".") ^0
return 0 - 1
return int(t)
def own_swap():
number("km a year", 1, 100000) => km
if km < 0:
return
number("km per litre now", 1, 99) => a
if a < 0:
return
number("km per litre after", 1, 99) => b
if b < 0:
return
("At " + commas(km) + " km a year: " + t1(fuel.litres(km, a)) + " litres now, " + t1(fuel.litres(km, b)) + " after; " + t1(fuel.per_100(a)) + " and " + t1(fuel.per_100(b)) + " litres per 100 km.") ^0
if b > a:
("The swap saves " + t1(fuel.saved(km, a, b)) + " litres a year.") ^0
elif b < a:
("The swap uses " + t1(fuel.saved(km, b, a)) + " litres a year more.") ^0
else:
"The swap changes nothing." ^0
def own_trip():
number("speed out, km/h", 1, 200) => a
if a < 0:
return
number("speed back, km/h", 1, 200) => b
if b < 0:
return
("Two legs of the same length at " + str(a) + " and " + str(b) + " km/h: the mean of the speeds is " + t1(fuel.tenths_of(a + b, 2)) + ", the average speed " + t1(fuel.average(a, b)) + ".") ^0
if a == b:
"At one speed they are the same." ^0
elif fuel.tenths_of(a + b, 2) == fuel.average(a, b):
"Rounded to a tenth they look the same; the average is still the lower, as it always is: more of the time is spent on the slower leg." ^0
else:
"The average is the lower, always: more of the time is spent on the slower leg." ^0
"== Fuel economy ==" ^0
"Two cars, a round trip, and the scale that adds up." ^0
True => running
while running:
"" ^0
"1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit" ^0
plain(input("choice> ")) => choice
if choice == "1":
show_cars()
elif choice == "2":
show_swaps()
elif choice == "3":
show_trip()
elif choice == "4":
own_swap()
elif choice == "5":
own_trip()
elif choice == "6":
False => running
else:
"Pick a number from 1 to 6." ^0
"Bye." ^0
Python projection (main.py)
import fuel
def plain(s):
i = 0
j = len(s)
while i < j and s[i] == " ":
i = i + 1
while j > i and s[j - 1] == " ":
j = j - 1
return s[i:j]
def pad(s, n):
out = s
while len(out) < n:
out = out + " "
return out
def lpad(s, n):
out = s
while len(out) < n:
out = " " + out
return out
def digits(t):
for c in t:
if c < "0" or c > "9":
return False
return len(t) > 0
def commas(n):
s = str(n)
out = ""
k = 0
i = len(s)
while i > 0:
if k == 3:
out = "," + out
k = 0
out = s[i - 1] + out
k = k + 1
i = i - 1
return out
def t1(t):
return commas(int((t - t % 10) / 10)) + "." + str(t % 10)
def show_cars():
print("Two cars, each driven 10,000 km a year; the household can afford to replace one:")
for c in fuel.cars():
print(" " + pad(c[0], 7) + lpad(str(c[2]), 2) + " km/L now, " + lpad(str(c[3]), 2) + " with its replacement: a gain of " + str(c[3] - c[2]) + " km/L")
def show_swaps():
print("Fuel a year, now and after each swap:")
print(" " + pad("car", 7) + lpad("now", 10) + lpad("after", 10) + lpad("saved", 10) + " L/100 km, now and after")
s = []
for c in fuel.cars():
v = fuel.saved(c[1], c[2], c[3])
s = s + [v]
print(" " + pad(c[0], 7) + lpad(t1(fuel.litres(c[1], c[2])) + " L", 10) + lpad(t1(fuel.litres(c[1], c[3])) + " L", 10) + lpad(t1(v) + " L", 10) + " " + t1(fuel.per_100(c[2])) + " and " + t1(fuel.per_100(c[3])))
print("A gain of 20 km/L is five times a gain of 4, and the van's swap saves " + t1(s[0]) + " litres a year to the hybrid's " + t1(s[1]) + ". Fuel used is distance divided by km/L, so a gain counts most where km/L is lowest; in litres per 100 km the van gains " + t1(fuel.tenths_of(100 * 4, 8 * 12)) + " and the sedan " + t1(fuel.tenths_of(100 * 20, 20 * 40)) + ".")
def show_trip():
t = fuel.trip()
print(str(t[0]) + " km out at " + str(t[1]) + " km/h and " + str(t[0]) + " km back at " + str(t[2]) + " km/h: " + str(int(t[0] / t[1])) + " hours out and " + str(int(t[0] / t[2])) + " back.")
print("The mean of the two speeds is " + t1(fuel.tenths_of(t[1] + t[2], 2)) + " km/h. The trip's average is " + str(2 * t[0]) + " km in " + str(int(t[0] / t[1]) + int(t[0] / t[2])) + " hours, " + t1(fuel.average(t[1], t[2])) + " km/h: the slow leg takes longer, so it counts for more of the time.")
def number(prompt, lo, hi):
t = plain(input(prompt + " (" + str(lo) + " to " + str(hi) + ")> "))
if t == "":
print("Cancelled.")
return 0 - 1
if len(t) > len(str(hi)) or not digits(t) or int(t) < lo or int(t) > hi:
print("Type a whole number from " + str(lo) + " to " + str(hi) + ".")
return 0 - 1
return int(t)
def own_swap():
km = number("km a year", 1, 100000)
if km < 0:
return
a = number("km per litre now", 1, 99)
if a < 0:
return
b = number("km per litre after", 1, 99)
if b < 0:
return
print("At " + commas(km) + " km a year: " + t1(fuel.litres(km, a)) + " litres now, " + t1(fuel.litres(km, b)) + " after; " + t1(fuel.per_100(a)) + " and " + t1(fuel.per_100(b)) + " litres per 100 km.")
if b > a:
print("The swap saves " + t1(fuel.saved(km, a, b)) + " litres a year.")
elif b < a:
print("The swap uses " + t1(fuel.saved(km, b, a)) + " litres a year more.")
else:
print("The swap changes nothing.")
def own_trip():
a = number("speed out, km/h", 1, 200)
if a < 0:
return
b = number("speed back, km/h", 1, 200)
if b < 0:
return
print("Two legs of the same length at " + str(a) + " and " + str(b) + " km/h: the mean of the speeds is " + t1(fuel.tenths_of(a + b, 2)) + ", the average speed " + t1(fuel.average(a, b)) + ".")
if a == b:
print("At one speed they are the same.")
elif fuel.tenths_of(a + b, 2) == fuel.average(a, b):
print("Rounded to a tenth they look the same; the average is still the lower, as it always is: more of the time is spent on the slower leg.")
else:
print("The average is the lower, always: more of the time is spent on the slower leg.")
print("== Fuel economy ==")
print("Two cars, a round trip, and the scale that adds up.")
running = True
while running:
print("")
print("1) the cars 2) which swap saves more 3) the round trip 4) a swap of your own 5) a trip of your own 6) quit")
choice = plain(input("choice> "))
if choice == "1":
show_cars()
elif choice == "2":
show_swaps()
elif choice == "3":
show_trip()
elif choice == "4":
own_swap()
elif choice == "5":
own_trip()
elif choice == "6":
running = False
else:
print("Pick a number from 1 to 6.")
print("Bye.")
fuel.eml
eml# P178 fuel economy - a household's two cars and a round trip. As in the
# corpus case the-van-gaining-four-saved-more-than-the-hybrid-gaining-twenty,
# fuel used is distance divided by kilometres per litre, so a gain in km/L
# saves the most where km/L is lowest: litres per 100 km is the scale that
# adds up. And as in the-average-speed-was-the-mean-of-the-legs, the average
# speed of a trip is its distance over its time, and over two equal legs that
# is not the mean of the two speeds. Litres are kept in tenths, rounded
# half-up, from exact integer arithmetic.
def cars():
# [name, km a year, km per litre now, km per litre of its replacement]
return [["van", 10000, 8, 12], ["sedan", 10000, 20, 40]]
def tenths_of(num, den):
# num / den in tenths, rounded half-up
num * 20 + den => y
return int((y - y % (2 * den)) / (2 * den))
def litres(km, kmpl):
# litres a year, in tenths
return tenths_of(km, kmpl)
def saved(km, before, after):
# litres saved a year, in tenths: the exact difference, rounded once
return tenths_of(km * (after - before), before * after)
def per_100(kmpl):
# litres per 100 km, in tenths
return tenths_of(100, kmpl)
def trip():
# [km each way, speed out, speed back]
return [60, 30, 60]
def average(a, b):
# the average speed over two legs of equal length, in tenths of a km/h
return tenths_of(2 * a * b, a + b)
Python projection (fuel.py)
def cars():
return [["van", 10000, 8, 12], ["sedan", 10000, 20, 40]]
def tenths_of(num, den):
y = num * 20 + den
return int((y - y % (2 * den)) / (2 * den))
def litres(km, kmpl):
return tenths_of(km, kmpl)
def saved(km, before, after):
return tenths_of(km * (after - before), before * after)
def per_100(kmpl):
return tenths_of(100, kmpl)
def trip():
return [60, 30, 60]
def average(a, b):
return tenths_of(2 * a * b, a + b)