unit_convert
Convert quantities between units with a dimensional check and an exact conversion factor: SI units with all prefixes, units accepted with the SI, and US customary and imperial units from a bundled dated table built from the SI Brochure (9th ed.) and NIST SP 811. Parses compound units (km/h, kg*m/s^2, J/(kg*K), kWh, m²) and converts temperatures in degC, degF, degR and K with their offsets.
Install
/tools install unit_convert /tools install unit_convert@1.0.0
In a console session, or let the model find it in normal mode: axlr_catalog describes it and axlr_install_tool asks for the same install card. The card reads catalog axlr · unit_convert 1.0.0 · verified once the index signature, the manifest digest and every file digest check out. Then the model runs it with axlr_run_tool unit_convert; each run is approved as a local_exec.
Arguments
One JSON object on stdin, validated against the schema before the program starts.
| name | type | required | default | meaning |
|---|---|---|---|---|
value | number | string | no | 1 | Number or decimal string |
from | string | no | Unit expression: names, SI prefixes, * / ^ ( ), juxtaposition, superscripts. length ≤ 200 | |
to | string | no | Omitted: SI base units. length ≤ 200 | |
temperature | string | no | "absolute" | Bare temperature units: with offsets (absolute) or as intervals. one of "absolute", "difference" |
precision | integer | no | 15 | Significant digits when the decimal does not terminate. ≥ 1; ≤ 50 |
list_units | boolean | no | List the table's units, prefixes and sources |
Input schema (JSON)
{
"type": "object",
"additionalProperties": false,
"properties": {
"value": {
"type": [
"number",
"string"
],
"default": 1,
"description": "Number or decimal string"
},
"from": {
"type": "string",
"maxLength": 200,
"description": "Unit expression: names, SI prefixes, * / ^ ( ), juxtaposition, superscripts"
},
"to": {
"type": "string",
"maxLength": 200,
"description": "Omitted: SI base units"
},
"temperature": {
"type": "string",
"enum": [
"absolute",
"difference"
],
"default": "absolute",
"description": "Bare temperature units: with offsets (absolute) or as intervals"
},
"precision": {
"type": "integer",
"minimum": 1,
"maximum": 50,
"default": 15,
"description": "Significant digits when the decimal does not terminate"
},
"list_units": {
"type": "boolean",
"description": "List the table's units, prefixes and sources"
}
}
}
Example
Input
{
"value": 100,
"from": "km/h",
"to": "m/s"
}
Output (stdout)
{
"result_exact": "250/9",
"result": "27.7777777777778",
"dimension": "m s^-1"
}
Files
The command the install card registers is python3 unit_convert.py, run in the workspace with PATH and HOME as its only environment. Each file's SHA-256 is in the signed index; the console checks them before showing the card and again before writing.
unit_convert.py · sha256 e0a04af242074d2574b7eb1314a68bacf1ec2545e01b3abc26f96ba9c2827689
#!/usr/bin/env python3
"""Convert a quantity between units with a dimensional check, using the bundled table
units.json (exact definitions from the SI Brochure, 9th ed., and NIST SP 811). Compound units
are parsed ("km/h", "kg*m/s^2", "J/(kg*K)", "kWh", "m²"), SI prefixes attach to SI and
SI-accepted units, and the conversion factor is an exact fraction. Temperatures in degC, degF,
degR and K are converted with their offsets when the whole unit is one temperature; inside a
compound unit (or with temperature "difference") they are temperature differences.
Input (JSON on stdin):
value number or decimal string, default 1
from unit expression
to unit expression; omitted: SI base units
temperature "absolute" (default) | "difference"
precision significant digits of the decimal rendering of a non-terminating result, default 15
list_units true: list the table instead
"""
import json
import pathlib
import re
import sys
from decimal import Decimal, localcontext
from fractions import Fraction
SUPERSCRIPTS = {"⁰": "0", "¹": "1", "²": "2", "³": "3", "⁴": "4", "⁵": "5", "⁶": "6", "⁷": "7", "⁸": "8", "⁹": "9", "⁻": "-"}
TOKEN = re.compile(r"\s*(?:(?P<name>(?:[^\W\d]|[°%′″])+)(?P<attached>-?\d+)?|(?P<number>\d+)|(?P<op>\*\*|[*/^()·×.+-]))")
def fail(message):
print(json.dumps({"error": message}, ensure_ascii=False))
sys.exit(2)
def load():
return json.loads((pathlib.Path(__file__).parent / "units.json").read_text(encoding="utf-8"))
TABLE = load()
DIMS = TABLE["dimensions"]
UNITS = TABLE["units"]
PREFIXES = {p: Fraction(v) for p, v in TABLE["prefixes"].items()}
NAMES = {}
for _symbol, _unit in UNITS.items():
NAMES[_symbol] = _symbol
for _alias in _unit["aliases"]:
NAMES.setdefault(_alias, _symbol)
TEMPERATURE_SYMBOLS = {"K", "degC", "degF", "degR"}
class Quantity:
def __init__(self, factor=Fraction(1), dims=None, exact=True):
self.factor, self.dims, self.exact = factor, dims or [0] * len(DIMS), exact
def mul(self, other, sign=1):
factor = self.factor * other.factor if sign == 1 else self.factor / other.factor
return Quantity(factor, [a + sign * b for a, b in zip(self.dims, other.dims)], self.exact and other.exact)
def power(self, n):
return Quantity(self.factor ** n, [a * n for a in self.dims], self.exact)
def unit_quantity(symbol, prefix=None):
unit = UNITS[symbol]
if unit["exact"]:
factor, exact = Fraction(unit["factor"]), True
else:
factor, exact = Fraction(Decimal(unit["factor_decimal"])), False
if prefix:
factor *= PREFIXES[prefix]
return Quantity(factor, list(unit["dimension"]), exact)
def resolve(name):
"""(symbol, prefix) for a unit name: an exact symbol or alias first, then prefix + unit."""
if name in NAMES:
return NAMES[name], None
for prefix in sorted(PREFIXES, key=len, reverse=True):
rest = name[len(prefix):]
if name.startswith(prefix) and rest in NAMES and UNITS[NAMES[rest]]["prefixable"]:
return NAMES[rest], prefix
return None, None
def normalise(text):
out, previous_super = [], False
for ch in text:
if ch in SUPERSCRIPTS:
if not previous_super:
out.append("^")
out.append(SUPERSCRIPTS[ch])
previous_super = True
else:
out.append(ch)
previous_super = False
return "".join(out)
def tokenize(text):
text = normalise(text)
tokens, pos = [], 0
while pos < len(text):
if text[pos:].strip() == "":
break
m = TOKEN.match(text, pos)
if not m or m.end() == pos:
fail(f"cannot read the unit at '{text[pos:].strip()}'")
if m.group("name"):
tokens.append(("name", m.group("name")))
if m.group("attached"):
tokens.append(("op", "^"))
tokens.append(("int", int(m.group("attached"))))
elif m.group("number"):
tokens.append(("int", int(m.group("number"))))
else:
tokens.append(("op", m.group("op")))
pos = m.end()
return tokens
class Parser:
def __init__(self, text):
self.text = text
self.tokens = tokenize(text)
self.i = 0
self.names = []
def peek(self):
return self.tokens[self.i] if self.i < len(self.tokens) else (None, None)
def take(self):
tok = self.peek()
self.i += 1
return tok
def parse(self):
if not self.tokens:
fail("empty unit")
q = self.expr()
if self.i != len(self.tokens):
fail(f"unexpected '{self.peek()[1]}' in unit '{self.text}'")
return q
def expr(self):
q = self.term()
while True:
kind, val = self.peek()
if kind == "op" and val in ("*", "·", "×", "."):
self.take()
q = q.mul(self.term())
elif kind == "op" and val == "/":
self.take()
q = q.mul(self.term(), -1)
elif kind == "name" or (kind == "op" and val == "("):
q = q.mul(self.term()) # juxtaposition: "N m"
else:
return q
def term(self):
q = self.atom()
kind, val = self.peek()
if kind == "op" and val in ("^", "**"):
self.take()
sign = 1
kind, val = self.peek()
if kind == "op" and val in ("-", "+"):
self.take()
sign = -1 if val == "-" else 1
kind, val = self.take()
if kind != "int":
fail(f"an exponent must be an integer in '{self.text}'")
if val > 12:
fail("exponents above 12 are not supported")
q = q.power(sign * val)
return q
def atom(self):
kind, val = self.take()
if kind == "name":
symbol, prefix = resolve(val)
if symbol is None:
fail(f"unknown unit '{val}' (list_units shows the table)")
self.names.append((symbol, prefix))
return unit_quantity(symbol, prefix)
if kind == "int":
if val == 0:
fail(f"a numeric factor in '{self.text}' must not be zero")
return Quantity(Fraction(val))
if kind == "op" and val == "(":
q = self.expr()
kind, val = self.take()
if (kind, val) != ("op", ")"):
fail(f"missing ')' in '{self.text}'")
return q
fail(f"unexpected '{val}' in unit '{self.text}'")
def dim_string(dims):
parts = [d if e == 1 else f"{d}^{e}" for d, e in zip(DIMS, dims) if e]
return " ".join(parts) if parts else "1 (dimensionless)"
def show(d):
d = d.normalize()
return format(d, "f") if -7 < d.adjusted() < 21 else str(d)
def decimal_string(fr, precision):
"""(text, rounded?) exact when the decimal expansion terminates within 60 digits."""
den = fr.denominator
twos = fives = 0
while den % 2 == 0:
den //= 2
twos += 1
while den % 5 == 0:
den //= 5
fives += 1
with localcontext() as ctx:
if den == 1 and max(twos, fives) <= 60 and len(str(abs(fr.numerator))) <= 60:
ctx.prec = 200
d = Decimal(fr.numerator) / Decimal(fr.denominator)
if len(d.normalize().as_tuple().digits) <= 60:
return show(d), False
ctx.prec = precision
d = Decimal(fr.numerator) / Decimal(fr.denominator)
return show(d), True
def bare_temperature(parser):
return len(parser.tokens) == 1 and parser.names and parser.names[0][0] in TEMPERATURE_SYMBOLS and parser.names[0][1] is None
def main():
try:
request = json.load(sys.stdin)
except ValueError as error:
fail(f"stdin is not JSON: {error}")
if not isinstance(request, dict):
fail("input must be a JSON object")
if request.get("list_units"):
print(json.dumps({"units": {s: {"definition": u["definition"], "aliases": u["aliases"], "prefixable": u["prefixable"],
"dimension": dim_string(u["dimension"]), "source": u["source"]} for s, u in UNITS.items()},
"prefixes": TABLE["prefixes"], "generated": TABLE["generated"], "source": TABLE["source"]}, ensure_ascii=False))
return
value = request.get("value", 1)
if isinstance(value, bool) or not isinstance(value, (int, float, str)):
fail("value must be a number or a decimal string")
try:
x = Fraction(str(value).strip())
except (ValueError, ZeroDivisionError):
fail("value must be a number or a decimal string")
source, target = request.get("from"), request.get("to")
if not isinstance(source, str) or not source.strip():
fail("from must be a unit expression")
if target is not None and (not isinstance(target, str) or not target.strip()):
fail("to must be a unit expression")
mode = request.get("temperature", "absolute")
if mode not in ("absolute", "difference"):
fail("temperature must be absolute or difference")
precision = request.get("precision", 15)
if isinstance(precision, bool) or not isinstance(precision, int) or not 1 <= precision <= 50:
fail("precision must be an integer from 1 to 50")
p_from = Parser(source)
q_from = p_from.parse()
if target is None:
q_to, p_to = Quantity(Fraction(1), list(q_from.dims)), None
target_text = dim_string(q_from.dims) if any(q_from.dims) else "1"
else:
p_to = Parser(target)
q_to = p_to.parse()
target_text = target
if q_from.dims != q_to.dims:
fail(f"incompatible units: {source} is {dim_string(q_from.dims)}, {target_text} is {dim_string(q_to.dims)}")
out = {"value": str(value), "from": source, "to": target_text, "dimension": dim_string(q_from.dims)}
affine = mode == "absolute" and p_to is not None and bare_temperature(p_from) and bare_temperature(p_to)
if affine:
t_from, t_to = TABLE["temperatures"][p_from.names[0][0]], TABLE["temperatures"][p_to.names[0][0]]
kelvin = (x + Fraction(t_from["offset"])) * Fraction(t_from["scale"])
result = kelvin / Fraction(t_to["scale"]) - Fraction(t_to["offset"])
out["temperature"] = "absolute: T/K = (t + offset) x scale on each side"
if kelvin < 0:
out["warning"] = "below absolute zero"
else:
factor = q_from.factor / q_to.factor
result = x * factor
text, rounded = decimal_string(factor, max(precision, 15))
out["factor"] = str(factor) if q_from.exact and q_to.exact else None
out["factor_decimal"] = text
if any(s in TEMPERATURE_SYMBOLS - {"K"} for s, _ in p_from.names + (p_to.names if p_to else [])):
out["temperature"] = "difference: degree units are read as temperature intervals here"
exact = q_from.exact and q_to.exact
text, rounded = decimal_string(result, precision)
out["result"] = text
out["result_exact"] = str(result) if exact else None
out["result_is_rounded"] = rounded or not exact
if not exact:
out["note"] = "an angle unit in degrees is irrational in radians: the result is a 50-digit approximation"
out["table"] = {"generated": TABLE["generated"], "source": TABLE["source"]}
print(json.dumps(out, ensure_ascii=False))
if __name__ == "__main__":
try:
main()
except (ArithmeticError, ValueError, RecursionError) as error:
fail(f"the numbers are out of the range this tool can compute: {type(error).__name__}")
units.json · sha256 24336a28d3b3aa1f70de9e230426f3b3bbcc960c5eac6d0a77dac9f8b9ec0c66
{
"generated": "2026-10-18",
"generator": "tools/catalog/data/unit_convert.py",
"source": "BIPM SI Brochure, 9th ed. (2019, v2.01 2022); NIST SP 811 (2008) App. B; NIST Handbook 44 App. C; IAU 2012 B2",
"dimensions": [
"m",
"kg",
"s",
"A",
"K",
"mol",
"cd"
],
"prefixes": {
"Q": "1000000000000000000000000000000",
"R": "1000000000000000000000000000",
"Y": "1000000000000000000000000",
"Z": "1000000000000000000000",
"E": "1000000000000000000",
"P": "1000000000000000",
"T": "1000000000000",
"G": "1000000000",
"M": "1000000",
"k": "1000",
"h": "100",
"da": "10",
"d": "1/10",
"c": "1/100",
"m": "1/1000",
"µ": "1/1000000",
"μ": "1/1000000",
"u": "1/1000000",
"n": "1/1000000000",
"p": "1/1000000000000",
"f": "1/1000000000000000",
"a": "1/1000000000000000000",
"z": "1/1000000000000000000000",
"y": "1/1000000000000000000000000",
"r": "1/1000000000000000000000000000",
"q": "1/1000000000000000000000000000000"
},
"temperatures": {
"K": {
"scale": "1",
"offset": "0"
},
"degC": {
"scale": "1",
"offset": "273.15"
},
"degF": {
"scale": "5/9",
"offset": "459.67"
},
"degR": {
"scale": "5/9",
"offset": "0"
}
},
"units": {
"m": {
"factor": "1",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"metre",
"meter"
],
"definition": "SI base unit of length",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"g": {
"factor": "1/1000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"gram"
],
"definition": "1/1000 kg (the kilogram is the SI base unit; prefixes attach to the gram)",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"s": {
"factor": "1",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"second"
],
"definition": "SI base unit of time",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"A": {
"factor": "1",
"dimension": [
0,
0,
0,
1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"ampere"
],
"definition": "SI base unit of electric current",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"K": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
1,
0,
0
],
"prefixable": true,
"aliases": [
"kelvin"
],
"definition": "SI base unit of thermodynamic temperature",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"mol": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
0,
1,
0
],
"prefixable": true,
"aliases": [
"mole"
],
"definition": "SI base unit of amount of substance",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"cd": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
0,
0,
1
],
"prefixable": true,
"aliases": [
"candela"
],
"definition": "SI base unit of luminous intensity",
"source": "SI Brochure 9th ed. (2019), Table 2",
"exact": true
},
"rad": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"radian"
],
"definition": "m/m",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"sr": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"steradian"
],
"definition": "m2/m2",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Hz": {
"factor": "1",
"dimension": [
0,
0,
-1,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"hertz"
],
"definition": "s-1",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"N": {
"factor": "1",
"dimension": [
1,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"newton"
],
"definition": "kg m s-2",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Pa": {
"factor": "1",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"pascal"
],
"definition": "N/m2",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"J": {
"factor": "1",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"joule"
],
"definition": "N m",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"W": {
"factor": "1",
"dimension": [
2,
1,
-3,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"watt"
],
"definition": "J/s",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"C": {
"factor": "1",
"dimension": [
0,
0,
1,
1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"coulomb"
],
"definition": "A s",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"V": {
"factor": "1",
"dimension": [
2,
1,
-3,
-1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"volt"
],
"definition": "W/A",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"F": {
"factor": "1",
"dimension": [
-2,
-1,
4,
2,
0,
0,
0
],
"prefixable": true,
"aliases": [
"farad"
],
"definition": "C/V",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"ohm": {
"factor": "1",
"dimension": [
2,
1,
-3,
-2,
0,
0,
0
],
"prefixable": true,
"aliases": [
"Ω",
"Ω"
],
"definition": "V/A",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"S": {
"factor": "1",
"dimension": [
-2,
-1,
3,
2,
0,
0,
0
],
"prefixable": true,
"aliases": [
"siemens"
],
"definition": "A/V",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Wb": {
"factor": "1",
"dimension": [
2,
1,
-2,
-1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"weber"
],
"definition": "V s",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"T": {
"factor": "1",
"dimension": [
0,
1,
-2,
-1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"tesla"
],
"definition": "Wb/m2",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"H": {
"factor": "1",
"dimension": [
2,
1,
-2,
-2,
0,
0,
0
],
"prefixable": true,
"aliases": [
"henry"
],
"definition": "Wb/A",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"lm": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
0,
0,
1
],
"prefixable": true,
"aliases": [
"lumen"
],
"definition": "cd sr",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"lx": {
"factor": "1",
"dimension": [
-2,
0,
0,
0,
0,
0,
1
],
"prefixable": true,
"aliases": [
"lux"
],
"definition": "lm/m2",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Bq": {
"factor": "1",
"dimension": [
0,
0,
-1,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"becquerel"
],
"definition": "s-1",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Gy": {
"factor": "1",
"dimension": [
2,
0,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"gray"
],
"definition": "J/kg",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"Sv": {
"factor": "1",
"dimension": [
2,
0,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"sievert"
],
"definition": "J/kg",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"kat": {
"factor": "1",
"dimension": [
0,
0,
-1,
0,
0,
1,
0
],
"prefixable": true,
"aliases": [
"katal"
],
"definition": "mol/s",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"degC": {
"factor": "1",
"dimension": [
0,
0,
0,
0,
1,
0,
0
],
"prefixable": false,
"aliases": [
"°C",
"celsius"
],
"definition": "degree Celsius: t/°C = T/K - 273.15; as a difference 1 °C = 1 K",
"source": "SI Brochure 9th ed. (2019), Table 4",
"exact": true
},
"min": {
"factor": "60",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"minute"
],
"definition": "60 s",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"h": {
"factor": "3600",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"hour"
],
"definition": "60 min = 3600 s",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"d": {
"factor": "86400",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"day"
],
"definition": "24 h = 86400 s",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"wk": {
"factor": "604800",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"week"
],
"definition": "7 d",
"source": "7 days of 86400 s",
"exact": true
},
"yr": {
"factor": "31557600",
"dimension": [
0,
0,
1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"year",
"a"
],
"definition": "Julian year, 365.25 d",
"source": "IAU; NIST SP 811 (2008), App. B.9 (year, 365.25 d)",
"exact": true
},
"au": {
"factor": "149597870700",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"astronomical_unit"
],
"definition": "149 597 870 700 m",
"source": "SI Brochure 9th ed. (2019), Table 8 (IAU 2012 Resolution B2)",
"exact": true
},
"ly": {
"factor": "9460730472580800",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"light_year"
],
"definition": "c x Julian year = 9 460 730 472 580 800 m",
"source": "IAU; c from SI Brochure 9th ed. (2019)",
"exact": true
},
"ha": {
"factor": "10000",
"dimension": [
2,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"hectare"
],
"definition": "1 hm2 = 10^4 m2",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"L": {
"factor": "1/1000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"l",
"litre",
"liter"
],
"definition": "1 dm3 = 10^-3 m3",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"t": {
"factor": "1000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"tonne"
],
"definition": "10^3 kg",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"eV": {
"factor": "801088317/5000000000000000000000000000",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"electronvolt"
],
"definition": "e x 1 V, e = 1.602176634e-19 C exactly",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": true
},
"angstrom": {
"factor": "1/10000000000",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"Å",
"Å"
],
"definition": "10^-10 m",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"bar": {
"factor": "100000",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [],
"definition": "10^5 Pa",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"in": {
"factor": "127/5000",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"inch"
],
"definition": "0.0254 m exactly",
"source": "NIST SP 811 (2008), App. B.8; 1959 agreement",
"exact": true
},
"ft": {
"factor": "381/1250",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"foot",
"feet"
],
"definition": "12 in = 0.3048 m exactly",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"yd": {
"factor": "1143/1250",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"yard"
],
"definition": "3 ft = 0.9144 m exactly",
"source": "NIST SP 811 (2008), App. B.8; 1959 agreement",
"exact": true
},
"mi": {
"factor": "201168/125",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"mile"
],
"definition": "5280 ft = 1609.344 m exactly (international mile)",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"nmi": {
"factor": "1852",
"dimension": [
1,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"nautical_mile"
],
"definition": "1852 m exactly",
"source": "NIST SP 811 (2008), App. B.8; SI Brochure 9th ed. (2019), Table 8 note",
"exact": true
},
"acre": {
"factor": "316160658/78125",
"dimension": [
2,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "43 560 ft2 = 4046.8564224 m2 (international foot)",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"lb": {
"factor": "45359237/100000000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"pound"
],
"definition": "avoirdupois pound, 0.45359237 kg exactly",
"source": "NIST SP 811 (2008), App. B.8; 1959 agreement",
"exact": true
},
"oz": {
"factor": "45359237/1600000000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"ounce"
],
"definition": "lb/16 = 28.349523125 g",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"st": {
"factor": "317514659/50000000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"stone"
],
"definition": "14 lb",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"ton": {
"factor": "45359237/50000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"short_ton"
],
"definition": "short ton, 2000 lb",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"long_ton": {
"factor": "317514659/312500",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "long ton, 2240 lb",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"gr": {
"factor": "6479891/100000000000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"grain"
],
"definition": "lb/7000 = 64.79891 mg",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"ozt": {
"factor": "19439673/625000000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"troy_ounce"
],
"definition": "480 gr = 31.1034768 g",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"ct": {
"factor": "1/5000",
"dimension": [
0,
1,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"carat"
],
"definition": "metric carat, 200 mg",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"gal": {
"factor": "473176473/125000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"gallon",
"us_gal"
],
"definition": "US gallon, 231 in3 = 3.785411784 L",
"source": "NIST SP 811 (2008), App. B.8; NIST Handbook 44 (2024), App. C",
"exact": true
},
"qt": {
"factor": "473176473/500000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"quart"
],
"definition": "US liquid quart, gal/4",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"pt": {
"factor": "473176473/1000000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"pint"
],
"definition": "US liquid pint, gal/8",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"cup": {
"factor": "473176473/2000000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "US cup, gal/16 = 8 fl oz",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"floz": {
"factor": "473176473/16000000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"fl_oz",
"fluid_ounce"
],
"definition": "US fluid ounce, gal/128",
"source": "NIST SP 811 (2008), App. B.8; NIST Handbook 44 (2024), App. C",
"exact": true
},
"tbsp": {
"factor": "473176473/32000000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"tablespoon"
],
"definition": "US tablespoon, fl oz/2",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"tsp": {
"factor": "157725491/32000000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"teaspoon"
],
"definition": "US teaspoon, fl oz/6",
"source": "NIST Handbook 44 (2024), App. C",
"exact": true
},
"bbl": {
"factor": "9936705933/62500000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"barrel"
],
"definition": "oil barrel, 42 US gal",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"imp_gal": {
"factor": "454609/100000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"imperial_gallon"
],
"definition": "imperial gallon, 4.54609 L exactly",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"imp_pt": {
"factor": "454609/800000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"imperial_pint"
],
"definition": "imperial pint, imp gal/8",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"imp_floz": {
"factor": "454609/16000000000",
"dimension": [
3,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"imperial_fluid_ounce"
],
"definition": "imperial fluid ounce, imp gal/160",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"gn": {
"factor": "196133/20000",
"dimension": [
1,
0,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"g0",
"standard_gravity"
],
"definition": "standard acceleration of gravity, 9.80665 m/s2",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"lbf": {
"factor": "8896443230521/2000000000000",
"dimension": [
1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"pound_force"
],
"definition": "lb x g_n = 4.4482216152605 N",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"kgf": {
"factor": "196133/20000",
"dimension": [
1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"kilogram_force"
],
"definition": "kg x g_n = 9.80665 N",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"psi": {
"factor": "8896443230521/1290320000",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "lbf/in2",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"atm": {
"factor": "101325",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"atmosphere"
],
"definition": "standard atmosphere, 101 325 Pa",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"torr": {
"factor": "20265/152",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"Torr"
],
"definition": "atm/760",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"mmHg": {
"factor": "26664477483/200000000",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "conventional millimetre of mercury, 133.322387415 Pa",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"inHg": {
"factor": "3386388640341/1000000000",
"dimension": [
-1,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "conventional inch of mercury, 25.4 mmHg",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"cal": {
"factor": "523/125",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"calorie"
],
"definition": "thermochemical calorie, 4.184 J exactly",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"cal_IT": {
"factor": "10467/2500",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [],
"definition": "International Table calorie, 4.1868 J exactly",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"Btu": {
"factor": "52752792631/50000000",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"BTU",
"btu"
],
"definition": "International Table Btu, 1055.05585262 J",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"Wh": {
"factor": "3600",
"dimension": [
2,
1,
-2,
0,
0,
0,
0
],
"prefixable": true,
"aliases": [
"watt_hour"
],
"definition": "W x h = 3600 J",
"source": "SI Brochure 9th ed. (2019), Table 8 (hour)",
"exact": true
},
"Ah": {
"factor": "3600",
"dimension": [
0,
0,
1,
1,
0,
0,
0
],
"prefixable": true,
"aliases": [
"amp_hour"
],
"definition": "A x h = 3600 C",
"source": "SI Brochure 9th ed. (2019), Table 8 (hour)",
"exact": true
},
"hp": {
"factor": "37284993579113511/50000000000000",
"dimension": [
2,
1,
-3,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"horsepower"
],
"definition": "mechanical horsepower, 550 ft lbf/s = 745.69987158227022 W",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"hp_metric": {
"factor": "588399/800",
"dimension": [
2,
1,
-3,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"PS"
],
"definition": "metric horsepower, 75 kgf m/s = 735.49875 W",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"mph": {
"factor": "1397/3125",
"dimension": [
1,
0,
-1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "mi/h",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"kn": {
"factor": "463/900",
"dimension": [
1,
0,
-1,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"knot"
],
"definition": "nmi/h",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"percent": {
"factor": "1/100",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"%"
],
"definition": "1/100",
"source": "ISO 80000-1",
"exact": true
},
"ppm": {
"factor": "1/1000000",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [],
"definition": "10^-6",
"source": "ISO 80000-1",
"exact": true
},
"degF": {
"factor": "5/9",
"dimension": [
0,
0,
0,
0,
1,
0,
0
],
"prefixable": false,
"aliases": [
"°F",
"fahrenheit"
],
"definition": "degree Fahrenheit: T/K = (t/°F + 459.67) x 5/9; as a difference 5/9 K",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"degR": {
"factor": "5/9",
"dimension": [
0,
0,
0,
0,
1,
0,
0
],
"prefixable": false,
"aliases": [
"°R",
"rankine"
],
"definition": "degree Rankine, 5/9 K",
"source": "NIST SP 811 (2008), App. B.8",
"exact": true
},
"deg": {
"factor": null,
"factor_decimal": "0.01745329251994329576923690768488612713442871888542",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"°",
"degree"
],
"definition": "pi/180 rad",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": false
},
"arcmin": {
"factor": null,
"factor_decimal": "0.00029088820866572159615394846141476878557381198142",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"′"
],
"definition": "(1/60) degree",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": false
},
"arcsec": {
"factor": null,
"factor_decimal": "0.00000484813681109535993589914102357947975956353302",
"dimension": [
0,
0,
0,
0,
0,
0,
0
],
"prefixable": false,
"aliases": [
"″"
],
"definition": "(1/60) arcmin",
"source": "SI Brochure 9th ed. (2019), Table 8",
"exact": false
}
}
}
Where it is served
The registry serves only AXLR clients, so a browser gets 403; fetch with a User-Agent that starts with axlr:
curl -A axlr-docs/1.0 -O https://registry.underpassai.com/tools/unit_convert/1.0.0/manifest.json
curl -A axlr-docs/1.0 -O https://registry.underpassai.com/tools/unit_convert/1.0.0/unit_convert.py
curl -A axlr-docs/1.0 -O https://registry.underpassai.com/tools/unit_convert/1.0.0/units.json