- when multiplying or dividing units resulting units need to use same
order always, e.g.
let m: Meter let s: Second doAssert typeof(m * s) == typeof(s * m) == m•s
We can do this by having a specific order of all units, like an importance ranking. Then when combining reflect that. Once we have more complex units it’s probably a good idea to bring back the idea of the
SiUnitcompile time object, which should abstract away many parts and result in simpler handling, because we don’t have to work with strings. Essentially should be able to define a comparison operator of units that solves this for us and a serialization procedure, which turns theSiUnitback into adistinctunit. - add remaining SI prefixes and automate their units, i.e. write a macro that generates all units with all prefixes
- add combinatorical units
- add remaining standard units
- add natural units (how to best do it? Something like “NaturalLength” for full name?)
- add imperial units
- add physical constants
- add support for affine unit conversions (Celsius -> Fahrenheit)
- add parsing of english language units (“meterPerSecondSquared”); low priority
- generate all common units as english language (low priority). But generation is much easier than parsing?
Sounds like a lot…
In no particular order things that either are or need to be supported:
## The following already work unless `TODO` (not all units implemented)
block:
# defining simple units
let mass = 5.kg
let a = 9.81.m•s⁻²
block:
# addition and subtraction of same units
let a = 5.kg
let b = 10.kg
check typeof(a + b) == Kg
check a + b == 15.kg
check typeof(a - b) == Kg
check a - b == 15.kg
block:
# addition and subtraction of units of the same ``quantity`` but different scale
let a = 5.kg
let b = 500.g
check typeof(a + b) == Kg
check a + b == 5.5.kg
# if units do not match, the SI unit is used!
block:
# product of prefixed SI unit keeps same prefix unless multiple units of same quantity involved
let a = 1.m•s⁻²
let b = 500.g
check typeof(a + b) == Gram•Meter•Second⁻²
check typeof(a + b) == MilliNewton
check a + b == 500.g•m•s⁻²
block:
let mass = 5.kg
let a = 9.81.m•s⁻²
# unit multiplication has to be commutative
let F: Newton = mass * a
let F2: Newton = a * mass # TODO
# unit division works as expected
check typeof(F / mass) == Meter•Second⁻²
check F / mass == a
block:
# conversion between units of the same quantity
let f = 10.N
check typeof(f.to(kN)) == KiloNewton
check f.to(kN) == 0.01.kN
block:
# pre-defined physical constants
let E_e⁻_rest: Joule = m_e * c^2 # math operations `*cannot*` use superscripts!
# m_e = electron mass in kg
# c = speed of light in vacuum in m/s
block:
# automatic CT error if argument of e.g. sin, ln are not unit less
let x = 5.kg
let y = 10.kg
discard sin(x / y) ## compiles gives correct result (~0.48)
let x2 = 10.m
# sin(x2 / y) ## errors at CT due to non unit less argument
block:
# units using english language (using accented quotes)
let a = 10.`meter per second squared`
let b = 5.`kilogram meter per second squared`
check typeof(a) == Meter•Second⁻²
check typeof(b) == Newton
check a == 10.m•s⁻²
check b == 5.N
## Yet to be implemented
block:
# imperial units
let mass = 100.lbs
block:
# mixing of non SI and SI units (via conversion to SI units)
let m1 = 100.lbs
let m2 = 10.kg
check typeof(m1 + m2) == Kg
check m1 + m2 == 55.3592.Kg
block:
# natural unit support (c = 1, h = 1)
let speed: NaturalVelocity = 0.1.UnitLess # fraction of c
let m_e: NaturalMass = 511.keV
# math between natural units remains natural
let p: NaturalMomentum = speed * m_e
check p == 51.1.keV
block:
# auto conversion of natural units
let a = 10.MeV
let b = 200.eV
check typeof(a / b) == UnitLess # `UnitLess` is
check a / b == 50_000.UnitlessThings to note:
- real units use capital letters and are verbose
- shorthands defined for all typical units
- conversion of numbers to units done using `.` call and using shorthand names
- `•` symbol is product of units to allow unambiguous parsing of units
- no division of units, but negative exponents
- exponents are in superscript
- usage of `•` and superscript is to circumvent Nim’s identifier rules!
- SI units are the base. If ambiguous operation that can be solved by unit conversion, SI units are used.
- math operations cannot use superscripts!
- physical units are defined
- conversion from prefixed SI unit to non prefixed SI unit only happens if multiple prefixed units of same quantity involved
UnitLessis adistinct floatunit that has a converter tofloat(such thatUnitLessmagically works with math functions expecting floats).