'use strict'; // length-conversion.cjs -- METHOD DECK (X063), reversible length unit conversion. // Factors are the exact meter-equivalents from NIST SP 811 (2008 ed.), Appendix B.8 "Length". 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); } // Meters per 1 unit. All exact by definition (NIST SP 811 Appendix B.8). const TO_METERS = { mm: 0.001, cm: 0.01, m: 1, km: 1000, in: 0.0254, ft: 0.3048, yd: 0.9144, mi: 1609.344, nmi: 1852, }; const UNITS = Object.keys(TO_METERS); module.exports = { slug: 'length-conversion', title: 'Length conversion', deck_category: 'units', description: 'Converts a length between metric and US/imperial units using exact NIST SP 811 meter-equivalents.', inputs: [ { name: 'value', type: 'number', unit: 'from_unit', required: true, description: 'The length to convert' }, { 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 length' } ], steps: [ 'Look up the exact meter-equivalent of from_unit and of to_unit from the NIST SP 811 table.', 'Convert the input to meters: meters = value * meters_per(from_unit).', 'Convert meters to the target unit: result = meters / meters_per(to_unit).', 'Round result to 6 significant figures.', ], constants: [ { name: 'mm', value: 0.001, unit: 'm', source: 0 }, { name: 'cm', value: 0.01, unit: 'm', source: 0 }, { name: 'm', value: 1, unit: 'm', source: 0 }, { name: 'km', value: 1000, unit: 'm', source: 0 }, { name: 'in', value: 0.0254, unit: 'm', source: 0 }, { name: 'ft', value: 0.3048, unit: 'm', source: 0 }, { name: 'yd', value: 0.9144, unit: 'm', source: 0 }, { name: 'mi', value: 1609.344, unit: 'm', source: 0 }, { name: 'nmi', value: 1852, unit: 'm', source: 0 }, ], sources: [ { kind: 'standard', value: 'NIST Special Publication 811 (2008 edition), Appendix B.8, Table for length', 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: 'in, ft, yd, mi, nmi are exact by international/nautical-mile definitions; mm, cm, km are exact SI decimal multiples of the meter.' }, ], disclaimer: null, questionText(inputs) { return `How many ${inputs.to_unit} are in ${inputs.value} ${inputs.from_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 (!TO_METERS.hasOwnProperty(from_unit)) throw new Error('from_unit must be one of: ' + UNITS.join(', ')); if (!TO_METERS.hasOwnProperty(to_unit)) throw new Error('to_unit must be one of: ' + UNITS.join(', ')); const meters = value * TO_METERS[from_unit]; const result = meters / TO_METERS[to_unit]; return { answer: `${fmtSig(result, 6)} ${to_unit}`, values: { result } }; }, examples: [ { name: 'worked example', inputs: { value: 5, from_unit: 'mi', to_unit: 'km' }, expected: { answer: '8.04672 km' }, check: 'By hand: 5 mi * 1609.344 m/mi = 8046.72 m = 8.04672 km exactly; already 6 significant figures.' }, { name: 'test vector: km to miles', inputs: { value: 100, from_unit: 'km', to_unit: 'mi' }, expected: { answer: '62.1371 mi' }, check: 'By hand: 100,000 m / 1609.344 m/mi = 62.137119...; rounded to 6 significant figures is 62.1371.' }, { name: 'test vector: inches to centimeters', inputs: { value: 12, from_unit: 'in', to_unit: 'cm' }, expected: { answer: '30.4800 cm' }, check: 'By hand: 12 in * 0.0254 m/in = 0.3048 m = 30.48 cm exactly, shown to 6 significant figures as 30.4800.' }, ], };