'use strict'; // fuel-economy-conversion.cjs -- METHOD DECK (X063), reversible fuel economy conversion. // mpg (US) and mpg (UK) use the exact NIST SP 811 mile (1609.344 m) over the exact US gallon // (3.785411784 L) or the exact UK imperial gallon (4.54609 L). L/100km is the RECIPROCAL rate // (liters consumed per 100 km travelled), so it is inversely related to km/L and to mpg. function roundSig(x, sig) { if (x === 0) return { value: 0, decimals: 0 }; const neg = x < 0; const ax = Math.abs(x); let exp = Math.floor(Math.log10(ax)); let decimals = Math.max(sig - exp - 1, 0); let factor = Math.pow(10, decimals); let value = Math.round(ax * factor) / factor; const newExp = value === 0 ? exp : Math.floor(Math.log10(value)); if (newExp !== exp) { decimals = Math.max(sig - newExp - 1, 0); factor = Math.pow(10, decimals); value = Math.round(ax * factor) / factor; } return { value: neg ? -value : value, decimals }; } function fmt(x, decimals) { return x.toLocaleString('en-US', { minimumFractionDigits: decimals, maximumFractionDigits: decimals }); } function fmtSig(x, sig) { const r = roundSig(x, sig); return fmt(r.value, r.decimals); } const KM_PER_MILE = 1609.344 / 1000; // exact, NIST SP 811 const L_PER_GAL_US = 3.785411784; // exact, NIST HB 44 const L_PER_GAL_UK = 4.54609; // exact, UK imperial gallon const UNITS = ['mpg_us', 'mpg_uk', 'l_100km', 'km_l']; const DISPLAY = { mpg_us: 'mpg (US)', mpg_uk: 'mpg (UK)', l_100km: 'L/100km', km_l: 'km/L' }; // Pivot unit is km/L (kilometers travelled per liter of fuel). mpg and km/L are direct-proportional // (higher = more efficient); L/100km is a RECIPROCAL rate (lower = more efficient), so converting // to or from it requires an inversion (100 / value), never a plain multiply. function toKmPerL(value, unit) { switch (unit) { case 'km_l': return value; case 'l_100km': if (value === 0) throw new Error('l_100km must be nonzero to invert to a rate'); return 100 / value; case 'mpg_us': return value * KM_PER_MILE / L_PER_GAL_US; case 'mpg_uk': return value * KM_PER_MILE / L_PER_GAL_UK; default: throw new Error('unreachable'); } } function fromKmPerL(kml, unit) { switch (unit) { case 'km_l': return kml; case 'l_100km': if (kml === 0) throw new Error('km/L must be nonzero to invert to L/100km'); return 100 / kml; case 'mpg_us': return kml * L_PER_GAL_US / KM_PER_MILE; case 'mpg_uk': return kml * L_PER_GAL_UK / KM_PER_MILE; default: throw new Error('unreachable'); } } module.exports = { slug: 'fuel-economy-conversion', title: 'Fuel economy conversion', deck_category: 'units', description: 'Converts fuel economy between mpg (US), mpg (UK), L/100km, and km/L, correctly inverting the L/100km reciprocal rate.', inputs: [ { name: 'value', type: 'number', unit: 'from_unit', required: true, description: 'The fuel economy figure to convert', min: 0 }, { name: 'from_unit', type: 'string', required: true, description: 'Unit of the input value', enum: UNITS }, { name: 'to_unit', type: 'string', required: true, description: 'Unit to convert into', enum: UNITS }, ], outputs: [ { name: 'result', unit: 'to_unit', description: 'The converted fuel economy figure' } ], steps: [ 'Convert the input to km/L (the pivot unit): km/L = value directly if already km/L; km/L = 100/value if L/100km (an inversion, since L/100km is a reciprocal rate); km/L = value * 1.609344/3.785411784 if mpg (US); km/L = value * 1.609344/4.54609 if mpg (UK).', 'Convert km/L to the target unit: value = km/L directly if km/L; value = 100/(km/L) if L/100km (an inversion); value = km/L * 3.785411784/1.609344 if mpg (US); value = km/L * 4.54609/1.609344 if mpg (UK).', 'Round result to 6 significant figures.', ], constants: [ { name: 'km_per_mile', value: KM_PER_MILE, unit: 'km/mi', source: 0 }, { name: 'liters_per_us_gallon', value: L_PER_GAL_US, unit: 'L/gal', source: 1 }, { name: 'liters_per_uk_gallon', value: L_PER_GAL_UK, unit: 'L/gal', source: 1 }, ], sources: [ { kind: 'standard', value: 'NIST Special Publication 811 (2008 edition), Appendix B.8: mile = 1609.344 m exactly', title: 'Guide for the Use of the International System of Units (SI)', publisher: 'National Institute of Standards and Technology', retrieved_utc: '2026-09-30T19:29:48Z', note: 'Exact length definition used to convert miles to kilometers.' }, { kind: 'standard', value: 'NIST Handbook 44 (2026 ed.), Appendix C: US gallon = 3.785411784 L exactly; UK imperial gallon = 4.54609 L exactly', title: 'Specifications, Tolerances, and Other Technical Requirements for Weighing and Measuring Devices', publisher: 'National Institute of Standards and Technology', retrieved_utc: '2026-09-30T19:29:48Z', note: 'Exact volume definitions used for mpg (US) and mpg (UK).' }, ], disclaimer: null, questionText(inputs) { return `What is ${inputs.value} ${DISPLAY[inputs.from_unit]} in ${DISPLAY[inputs.to_unit]}?`; }, run(inputs) { const { value, from_unit, to_unit } = inputs || {}; if (typeof value !== 'number' || !isFinite(value)) throw new Error('value must be a finite number'); if (!UNITS.includes(from_unit)) throw new Error('from_unit must be one of: ' + UNITS.join(', ')); if (!UNITS.includes(to_unit)) throw new Error('to_unit must be one of: ' + UNITS.join(', ')); const kml = toKmPerL(value, from_unit); const result = fromKmPerL(kml, to_unit); return { answer: `${fmtSig(result, 6)} ${DISPLAY[to_unit]}`, values: { result } }; }, examples: [ { name: 'worked example', inputs: { value: 30, from_unit: 'mpg_us', to_unit: 'l_100km' }, expected: { answer: '7.84049 L/100km' }, check: 'By hand: km/L = 30 * 1.609344/3.785411784 = 12.754304...; L/100km = 100/12.754304... = 7.840486..., rounded to 6 significant figures is 7.84049.' }, { name: 'test vector: L/100km back to mpg (US) confirms the inversion', inputs: { value: 7.840486, from_unit: 'l_100km', to_unit: 'mpg_us' }, expected: { answer: '30.0000 mpg (US)' }, check: 'Inverting the worked example: km/L = 100/7.840486 = 12.754305...; mpg (US) = 12.754305 * 3.785411784/1.609344 = 30.0000..., recovering the original value.' }, { name: 'test vector: mpg (UK) to km/L', inputs: { value: 40, from_unit: 'mpg_uk', to_unit: 'km_l' }, expected: { answer: '14.1602 km/L' }, check: 'By hand: km/L = 40 * 1.609344/4.54609 = 14.16019...; rounded to 6 significant figures is 14.1602.' }, ], };