This repository contains source data for the MultiConvert app.
To build and test the data files, you need Node.js and UglifyJS (npm install uglify-js -g
). The build script build.sh
will load and validate all data files, run all tests, and if no errors are encountered, produce minified data files.
$ ./build.sh
Compiling...
194 unit types defined
16 functions defined
1194 units defined
2659 units defined or included
3 includes defined
119 elements defined
11 solvers or calculators defined
0 errors in data
0 warnings in data
865 tests executed
865 tests passed
0 tests failed
0 errors total
0 warnings total
Wrote mcdbmain.js
Wrote mcdbmisc.js
Minifying...
-rw-rw-r-- 1 user group 189969 May 1 18:52 mcdbmain.js
-rw-rw-r-- 1 user group 165284 May 1 18:52 mcdbmain.min.js
-rw-rw-r-- 1 user group 30999 May 1 18:52 mcdbmisc.js
-rw-rw-r-- 1 user group 26071 May 1 18:52 mcdbmisc.min.js
$
The minified data files are currently mostly useless to most people. If you are using this data in your own application, it is recommended to use the JSON source files for your own purposes and use the build script just for validation and testing.
Units in the MultiConvert database are identified by a lowercase letter followed by one or more digits. The following ranges are currently used:
range | file | usage |
---|---|---|
u0 ‑u49 |
base-si.json |
Base units and coherent derived units in the International System of Units (SI). |
u50 ‑u99 |
base-nonsi.json |
Base units and coherent derived units not recognized by SI. |
u100 ‑u199 |
derived-si.json |
Non-SI units accepted for use with SI. |
u200 ‑u299 |
derived-length.json |
Non-SI units of length. |
u300 ‑u399 |
derived-area.json |
Non-SI units of area. |
u400 ‑u499 |
derived-volume.json |
Non-SI units of volume. |
u500 ‑u599 |
derived-vel-acc.json |
Non-SI units of velocity and acceleration. |
u600 ‑u699 |
derived-mass.json |
Non-SI units of mass. |
u700 ‑u799 |
derived-force.json |
Non-SI units of force. |
u800 ‑u899 |
derived-time.json |
Non-SI units of time. |
u900 ‑u999 |
derived‑temperature.json |
Non-SI units of temperature. |
u1000 ‑u1099 |
derived-angle.json |
Non-SI units of angular displacement. |
u1100 ‑u1199 |
derived-power.json |
Non-SI units of power. |
u1200 ‑u1299 |
derived-pressure.json |
Non-SI units of pressure. |
u1300 ‑u1399 |
derived-frequency.json |
Non-SI units of frequency. |
u1400 ‑u1499 |
derived-voltage.json |
Non-SI units of voltage. |
u1500 ‑u1599 |
derived-current.json |
Non-SI units of current. |
u1600 ‑u1699 |
derived-data.json |
Units of data or information (bits and bytes). |
u1700 ‑u1799 |
derived-sheets.json |
Units of page or sheet count (quires, reams, and bales). |
u1800 ‑u1899 |
derived-hardness.json |
Units of hardness of materials. |
u1900 ‑u1999 |
derived-misc.json |
Units expressed with a single decimal number not included in other categories. |
u2000 ‑u2099 |
dimensionless.json |
Dimensionless units. |
n100 ‑n199 |
viscosity.json |
Units of kinematic viscosity. |
n200 ‑n299 |
shoe-size.json |
Shoe sizes. |
n1000 ‑n1001 |
clock-time.json |
Biel Mean Time (also known as Swatch Internet Time). |
z0 ‑z2 |
frequency-color.json frequency-pitch.json guaca.json |
Units not expressed with a single decimal number not included in other categories. |
z100 ‑z199 |
numeral-system.json |
Numeral systems (binary, octal, hexadecimal, Roman numerals, et cetera). |
z200 ‑z299 |
coordinate-system.json |
Coordinate systems (Cartesian, polar, spherical, et cetera). |
z300 ‑z399 |
color-space.json |
Color spaces (RGB, HSV, YIQ, YUV, et cetera). |
z1000 ‑z1999 |
clock-time.json |
Wall clock time in different time zones. |
k0 ‑k5 |
capacitor-code.json inductor-code.json resistor-code.json |
Color codes and EIA codes for electronic components. |
c0 ‑c19999 |
Units of currency. These are not present in this repository but generated dynamically by MultiConvert from third-party data. | |
d0 ‑d99 |
dependent.json |
Units for which conversion requires the specification of an independent variable (such as air temperature for Mach number). |
m0 ‑m999 |
medical.json |
Units of concentration of various medications. |
p0 ‑p99 |
planck.json |
Planck units. |
Identifiers starting with e
, f
, i
, s
, and t
are not used for units as they are used for other objects.
Identifiers starting with n
are generally used for units for which mathematically exact conversion is not possible. (For some reason Biel Mean Time has an n
identifier even though it's an exact conversion.)
Units created through the use of SI or IEEE prefixes or multiplication and division of base units are not defined in data files but derived mathematically, and as such are identified not by a single identifier but by a unit expression. For example:
expression | unit |
---|---|
u0_3 |
kilometers |
u0_-3 |
millimeters |
u0^2 |
square meters |
u0/u2 |
meters per second |
u10*u0 |
newton meters |
u700*u0_-2 |
dyne centimeters |
u51.10 |
kibibits (u51 × 210) |
u1602.20 |
mebibytes (u1602 × 220) |
u13/u0^2*u4 |
watts (u13 ) per square meter (u0^2 ) kelvin (u4 ) |
u1103/u210^2*u101*u902 |
British thermal units (u1103 ) per square foot (u210^2 ) hour (u101 ) degree Rankine (u902 ) |
u1/u0^0.5*u2^2 |
kilograms (u1 ) per square root meter (u0^0.5 ) square second (u2^2 ) |
As shown above, unit expressions can get arbitrarily complex.
Division in unit expressions has lower precedence than multiplication, so u0*u1/u2*u3
is equivalent to (u0*u1)/(u2*u3)
, not ((u0*u1)/u2)*u3
.
If you need to look up an identifier, you can use the included mcvt.js
utility program. You can look up by identifier, symbol, or name.
$ ./mcvt.js u0
d id type sym name dimension
- -- ---- --- ------ ---------
u0 unit m meters length
$ ./mcvt.js meters
d id type sym name dimension
- -- ---- --- ------ ---------
u0 unit m meters length
$
If multiple objects match your query, mcvt.js
will list all matched objects. An asterisk in the first column indicates the default specified in the file disambiguation.json
.
$ ./mcvt.js m
d id type sym name dimension
- ----- ---- --- ------------------- ---------
* u0 unit m meters length
u1300 unit m meters (wavelength) time^-1
$
You can look up unit expressions as well.
$ ./mcvt.js u1/u0^0.5*u2^2
d id type sym name dimension
- -------------- ---- ---------- --------------------------------------------- ------------------------
u1/u0^0.5*u2^2 unit kg/m⁰⸳⁵·s² kilograms per square root meter square second mass length^-0.5 time^-2
$
Consider the definition of the meter:
"u0": {
"symbol": "m",
"name": {
"en": {
"1": "meter",
"*": "meters"
}
},
"dimension": {
"length": 1
}
}
This is read as "u0
, the meter, is the base unit for length."
Consider the definition of the minute:
"u100": {
"symbol": "min",
"name": {
"en": {
"1": "minute",
"*": "minutes"
}
},
"multiplier": 60,
"dimension": {
"time": 1
}
}
This is read as "u100
, the minute, is 60 seconds (the base unit for time)."
Consider the definition of the liter:
"u107": {
"symbol": "L",
"name": {
"en": {
"1": "liter",
"*": "liters"
}
},
"divisor": 1000,
"dimension": {
"length": 3
}
}
This is read as "u107
, the liter, is one 1000th of a cubic meter (the base unit for length cubed, aka volume)."
Consider the definition of the knot:
"u163": {
"symbol": "kn",
"name": {
"en": {
"1": "knot",
"*": "knots"
}
},
"multiplier": 1852,
"divisor": 3600,
"dimension": {
"length": 1,
"time": -1
}
}
This is read as "u163
, the knot, is 1852/3600 meters per second (the base unit for length over time, aka velocity)."
Consider the definition of degrees Fahrenheit:
"u900": {
"symbol": "°F",
"name": {
"en": {
"1": "degree Fahrenheit",
"*": "degrees Fahrenheit"
}
},
"instructions": "S32 M5 D9 A273.15",
"dimension": {
"temperature": 1
}
}
This is read as "to convert from u900
, degrees Fahrenheit, to kelvin (the base unit for temperature), subtract 32, multiply by 5, divide by 9, and add 273.15." (To convert in the other direction, the instructions must of course be performed in reverse.)
The following instructions are allowed in the instructions
field:
instruction | operation | formula | reverse operation |
---|---|---|---|
A a |
add | x' = x + a | S a |
S a |
subtract | x' = x − a | A a |
Z a |
subtract from | x' = a − x | Z a |
M a |
multiply | x' = x × a | D a |
D a |
divide | x' = x ÷ a | M a |
G a |
divide into | x' = a ÷ x | G a |
P a |
power | x' = xa | R a |
R a |
root | x' = x1÷a | P a |
X a |
exponential | x' = ax | L a |
L a |
logarithm | x' = loga x | X a |
E a |
natural exp | x' = ex − a | N a |
N a |
natural log | x' = ln (x + a) | E a |
C a |
circumference | x' = x × π ÷ a | Q a |
Q a |
diameter | x' = x × a ÷ π | C a |
R2 |
sqrt |
x' = √x | P2 |
R3 |
cbrt |
x' = ∛x | P3 |
L2 |
log2 |
x' = log2 x | X2 |
L10 |
log10 |
x' = log10 x | X10 |
E0 |
exp |
x' = ex | N0 |
E1 |
expm1 |
x' = ex − 1 | N1 |
N0 |
log |
x' = ln x | E0 |
N1 |
log1p |
x' = ln (x + 1) | E1 |
C180 |
toRadians |
x' = x × π ÷ 180 | Q180 |
Q180 |
toDegrees |
x' = x × 180 ÷ π | C180 |
F1 |
sin |
x' = sin x | V1 |
F2 |
cos |
x' = cos x | V2 |
F3 |
tan |
x' = tan x | V3 |
F4 |
cot |
x' = cot x | V4 |
F5 |
sec |
x' = sec x | V5 |
F6 |
csc |
x' = csc x | V6 |
F7 |
sinh |
x' = sinh x | V7 |
F8 |
cosh |
x' = cosh x | V8 |
F9 |
tanh |
x' = tanh x | V9 |
F10 |
coth |
x' = coth x | V10 |
F11 |
sech |
x' = sech x | V11 |
F12 |
csch |
x' = csch x | V12 |
V1 |
asin |
x' = sin−1 x | F1 |
V2 |
acos |
x' = cos−1 x | F2 |
V3 |
atan |
x' = tan−1 x | F3 |
V4 |
acot |
x' = cot−1 x | F4 |
V5 |
asec |
x' = sec−1 x | F5 |
V6 |
acsc |
x' = csc−1 x | F6 |
V7 |
asinh |
x' = sinh−1 x | F7 |
V8 |
acosh |
x' = cosh−1 x | F8 |
V9 |
atanh |
x' = tanh−1 x | F9 |
V10 |
acoth |
x' = coth−1 x | F10 |
V11 |
asech |
x' = sech−1 x | F11 |
V12 |
acsch |
x' = csch−1 x | F12 |
Instructions such as integer divide, modulus, comparisons, gamma function, etc. are not available because they cannot be performed in reverse.
Scientific notation uses the underscore (_
instead of E
or e
) in the instructions
field. An instruction such as M2E3
will be interpreted as x' = e2x−3, not x' = 2000x. To get the latter, use the instruction M2_3
.
Consider the definition of the DIN #4 kinematic viscosity cup:
"n144": {
"symbol": "s",
"name": {
"en": {
"1": "second (DIN #4)",
"*": "seconds (DIN #4)"
}
},
"parser": "function (a) { return (a*4.57-452/a)/100 }",
"formatter": "function (a) { a *= 100; return (Math.sqrt(a*a+8263)+a)/9.14 }",
"dimension": {
"length": 2,
"time": -1
}
}
This is read as "to convert from n144
, seconds using DIN #4, to square meters per second (the base unit for kinematic viscosity), use the function f(a)=(a*4.57-452/a)/100
; to convert in the other direction, multiply by 100, then use the function f(a)=(sqrt(a*a+8263)+a)/9.14
."
The input to the parser
function and the output of the formatter
function need not be a number. Consider the definition of frequency described as musical pitch:
"z1": {
"name": {
"en": "note"
},
"datatype": "text",
"parser": [
"function (a) {",
" if (a.trim) a = a.trim();",
" if (!a) return NaN;",
" var i='CCDDEFFGGAAB'.indexOf(a[0].toUpperCase());",
" if (i < 0) return NaN;",
" a = a.substring(1);",
" if (a.trim) a = a.trim();",
" while (a) {",
" if (a[0] === '#' || a[0] === '\u266F') i++;",
" else if (a[0] === 'b' || a[0] === '\u266D') i--;",
" else if (a[0] !== '\u266E') break;"
" a = a.substring(1);",
" }",
" if (a.trim) a = a.trim();",
" if (!a.length || !isFinite(a)) a=4;",
" return (27.5 * Math.pow(2, (a * 12 + i - 9) / 12));",
"}"
],
"formatter": [
"function (a) {",
" if (!(a=Math.abs(a)) || !isFinite(a)) return '';",
" var i = Math.round(Math.log(a / 27.5) * 12 / Math.log(2) + 9);",
" a = Math.floor(i / 12);",
" return ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B'][i - 12 * a] + a;",
"}"
],
"dimension": {
"time": -1
}
}
The "datatype": "text"
key-value pair indicates that the parser
function takes a string and the formatter
function returns a string. The parser
and formatter
functions in this example have been prettified for readability. Most functions in the actual data files are minimized.
It is generally recommended for JavaScript functions in unit definitions to use syntax as archaic as possible for maximum compatibility, hence the use of function (a) { ... }
instead of a => { ... }
, the check for a.trim
, the use of var
instead of const
or let
, the expression Math.log(a / 27.5) * 12 / Math.log(2)
instead of Math.log2(a / 27.5) * 12
, etc.
Consider this (abbreviated) test case for length:
{
"name": "inches",
"u0_-3": 254000,
"u0_-2": 25400,
"u0_-1": 2540,
"u0": 254,
"u0_1": 25.4,
"u0_2": 2.54,
"u0_3": 0.254,
"u207_-6": 10000000000,
"u207": 10000,
"epsilon": 1E-12
}
This test case states that 254000 millimeters (u0_-3
), 25400 centimeters (u0_-2
), 2540 decimeters (u0_-1
), 254 meters (u0
), 25.4 decameters (u0_1
), 2.54 hectometers (u0_2
), 0.254 kilometers (u0_3
), 10000000000 microinches (u207_-6
), and 10000 inches (u207
) should all convert to each other. The actual number of conversions performed and verified is n2 where n is the number of key-value pairs. Conversions from a unit to itself are also included.
The epsilon
key-value pair states that the maximum allowed difference |a − b| between the actual result a and expected result b of a conversion shall be the greater of ( |a| + |b| ) · ε and ε (here ε = 10-12). This is often necessary because floating point has issues (if you know, you know). An epsilon of zero means a and b must be exactly equal (in the floating point sense, not the real number sense; if you know, you know); an epsilon of 1 means a and b may be anything as long as they have the same sign. Most test cases use an epsilon of 10-15 or 10-12. Some unlucky test cases may have an epsilon as large as 10-3; it is not recommended to have an epsilon larger than this.
Consider this test case for numeral system:
{
"name": "one half",
"z102": "0.1",
"z104": "0.2",
"z106": "0.3",
"z108": "0.4",
"z110": "0.5",
"z112": "0.6",
"z116": "0.8",
"z120": "0.A",
"z136": "0.I",
"z160": "0.U",
"inputs": {
"z120": "0.a",
"z136": "0.i"
},
"outputs": {
"z199": ""
}
}
In this test case, the values of 0.a
for z120
(vigesimal or base 20) and 0.i
for z136
(sexatrigesimal or base 36) should only be tested as inputs; they should not be tested as outputs because the lowercase letters of the expected output would not match the uppercase letters of the actual output (0.A
and 0.I
respectively). Similarly, the empty string for z199
(Roman numerals) should only be tested as an output (given a non-integer, the Roman numeral conversion returns an empty string); it should not be tested as an input because an empty string would result in the actual output of an empty string for every other unit, which will not match any of the expected outputs.