A surprising number of imperial-to-metric conversions are not measurements at all. They are definitions, fixed by treaty in 1959 and unchanged since, so rounding them is a choice you are making rather than a limit of the data.
Where the constant is exact, hard-code every digit and let output formatting decide the rounding. Baking 2.2 into a spreadsheet introduces an error near 0.2% — invisible on a parcel, material on a tonne of freight.
The US liquid gallon is 231 cubic inches, or 3.785411784 L exactly. The imperial gallon is 4.54609 L exactly. Nothing in a "gal" label says which one a document means, and the sub-units disagree in the opposite direction: an imperial fluid ounce is 28.4130625 mL, smaller than the US fluid ounce at 29.5735295625 mL, yet an imperial pint holds 20 of them against the US pint's 16 — roughly 568 mL against 473 mL. Fuel economy inherits the whole mess, so 30 mpg quoted in the UK is about 25 mpg in the US for the same car.
The rule that follows: never store a bare "gallons" field. Store litres, or tag the value explicitly as gal_us, and convert only at the display edge.
Nearly every other conversion is a single multiplication, which tempts people into writing a generic value * factor converter. Temperature breaks it, because Fahrenheit and Celsius have different zero points:
degC = (degF - 32) * 5 / 9
K = degC + 273.15
The trap is that a temperature difference converts differently from a temperature. A rise of 10 °C is a rise of 18 °F, not 50 °F, and a rise of 10 °C is exactly 10 K. Kelvin and Rankine are the only scales where you can safely multiply and divide, which is why thermodynamic formulas insist on them. If your codebase has one function that converts both readings and deltas, it is producing wrong answers for one of them.
| Tool | Good for |
|---|---|
GNU units | Command line, thousands of definitions, refuses incompatible conversions instead of guessing. Ships with macOS and most Linux distros. |
Python pint | Units attached to values inside your program, with NumPy support. Raises on dimensional mismatch. |
js-quantities, convert-units | JavaScript equivalents for front-end and Node work. |
| Frink | Interactive calculation where dimensions are tracked through arbitrary expressions, including currency and historical units. |
GNU units is the fastest thing to reach for, and it handles the affine case with dedicated functions rather than plain unit names:
$ units -t '1 mile' 'km'
1.609344
$ units -t 'tempF(72)' 'tempC' # absolute temperature
22.222222
$ units -t '10 degF' 'degC' # a difference
5.5555556
$ units -t '1 usgallon' 'litre'
3.7854118
$ units '1 kg' 'metre'
conformability error
That last line is the feature. A converter that returns a number for every input will happily turn mass into distance; one that errors catches the bug at the point you wrote it.
Binary floats cannot represent 0.1 exactly, so chained conversions drift: convert metres to feet to inches to metres a few thousand times and the value moves in the last digits. It rarely matters for display, and it matters a great deal for equality tests and for money. Convert once from the stored canonical unit rather than converting through intermediates, compare with a tolerance rather than ==, and use a decimal type for anything billed.
Currency deserves its own warning: it is not a unit conversion. USD to EUR has no fixed factor, the rate moves by the second, buy and sell rates differ, and a historical transaction must be converted at the rate on its own date. Any tool offering currency alongside metres and kilograms in one dropdown is caching a stale number. Store the amount with its currency code and the rate you applied, from a source that timestamps them.