What is in your opinion the best way to manage units in physical formulas with many types? I would want to know real, practical approaches that are reasonable to implement without much overhead. I also do not want to make everything a subtype, as that would defeat the purpose of having distinct units for distinct parameters.
Well, there is the world of ideas and practical problems. In practice
Marginal cases of astronomy or fixed-point embedded targets aside, the problem of physical computations is resolved by SI. All values must be in SI units. Period.
Considering engineering, e.g. communication, human-machine interfaces, problem specific languages, middleware, the solution is a subtype, because you need dimensioned values of statically indeterminable units.
So the pattern is always same:
Input dimensioned value, validate dimension, convert to SI.
Deal with SI values internally.
Convert from SI to the expected output unit or dimensioned value.
In short. Untis are for interfacing and never for computations.
I do not understand what you mean. I am using SI units but the problem is with operations and conversions. I will show an example:
type Meters is new Float;
type Seconds is new Float;
type Meters_Per_Second is new Float;
--- etc
type Radians is new Float;
type Degrees is new Float;
Suppose I have this types and similar in order to avoid using Seconds vs Meters where they don’t belong. Frequently, I have to do arithmethic with these to compute something that is another quantity e.g. Meters_Per_Second.
If I made everything a subtype, wouldn’t it preclude from having the type safety benefits?
One possibility would use SI Units checked and unchecked, which would have some runtime penalty.
Another possibility would be to use the Dimensionality extension from GNAT, this would you recommend? Or is it better to stick with standard Ada for the most part?
Last, I could use Units of Measurement which (maybe not?) has the same tradeoffs as the first one.
The software (automation systems) uses units strictly for input and output. For example there is an HMI. For US and the rest of the world it is same but units are switched, e.g. mph vs km/h. There is a configuration language where you can write formulae in dimensioned fashion like
12[A] * sin (Clock * 1[Hz]) -- Computed channel
The unit of Clock is [s]. So the frequency must be in Hz or equivalent.
But all computations are always in SI.
Note also that units are more or less arbitrary thing. Technically you can have just one base unit. Some units like temperature are no “real” physical values. Others are dimensionless. Practically no function can have dimensioned argument. That is why decree, radian, steradian have no dimension.
I slightly disagree with Dmitry here: SI isn’tnecessarily the best unit/system to use. There are multiple ways to “run the calculus”, but it really devolves to the ‘what’ in your problem.
To illustrate, consider a system with 9-bit bytes and 36-bit words (I forget the architecture, but it was before the 8-bit byte was quite standardized; it survives in several old standards) —or even the Setun trinary computer— which have native ranges of 2**9/2**36 and 3**X (I don’t recall Setsun’s “bit-length” for words). To properly model the former you would need to either pad-out a record, or use a bit-/trit-vector, or define a integer-range. Which route is ‘best’ depends on what you are going to be doing with it, and importantly the ‘display-type’ (or ‘storage-type’) need not be the same as your ‘native-type’.
To move to a bit more practical to your question, consider the value of 2**48 inches: this gives you approximately Pluto’s orbit (2**48 inches is roughly 97% of Pluto’s apogee distance) — thus, it might be perfectly appropriate to use inches for an orbital tracking system’s native unit, esp. because while not super common 48-bit does appear in some digital signal processing. — Does this mean that the ‘display’ should be in inches? No. You could display in feet, yards, km, or whatever, as that has no (direct) impact on the internal values.
SI is useful, but sometimes inappropriate or cumbersome in the sciences; this is why there’s so many “weird units” — instead of shoehorning in SI, the scientists at the start of these fields were measuring the raw data and thus used forms that were “native” to the problem-space, rather than trying to shove the problem-space into SI.
And that mirrors nicely to Ada: the best way to use Ada is to use the type-system to map your problem-space, and then you use that to solve your problem. — This inherently makes your code more portable if, for example, the compiler cannot generate Type Measure range -2**16..(2**48 - 1) then it is to error out, otherwise generate the appropriate code.
I find the GNAT dimensionality extension the best of all, since it provides the checking that is wanted during compile time. Do you know there is any interest towards standarizing it or something similar?
I think I will try that in case this approach ends up not working out.
Taken a look, definitely going to my bookmarks. Thanks