Replies: 8 comments 23 replies
-
This is exactly right, and beautifully expressed. That's why I like providing both
The temperatures we subtract, and the result of that subtraction, are clearly different in some way. It sounds like you're conceptualizing that difference as a difference in units. I suppose that's one way to go about it. An alternative way is to distinguish between a quantity of a given unit, and a quantity point of that unit. If we go that route, then the "hidden conversion" is not at all hidden; it's a simple fact that subtracting two quantity points of a unit produces a quantity of that unit. The quantity point concept encapsulates all of the various "arithmetic differences" that you would hope for: inability to add, inability to multiply, ability to apply an offset, and so on. And experience shows that end users can understand the quantity/point distinction very well in practice. |
Beta Was this translation helpful? Give feedback.
-
Quantities do not work that way. You can't define a "unit" whose zero represents a quantity other than zero. If you say that a length is "zero", then you have said everything there is to say about it. |
Beta Was this translation helpful? Give feedback.
-
Here's a meta-comment to help guide the discussion. When humans work with equations, quantities, and units, on pen and paper, we can bring our implicit knowledge into play. It's so easy and natural, we rarely realize we're doing it! Dropping and re-adding "rad" in angular equations; treating temperatures as quantities over here, but affine space types over there; we simply do whatever gets us the correct answer. When we try to make our quantity calculus precise enough for a machine to execute, we lose that flexibility. Suddenly, the humans have to care about little details that they glossed over before, because it makes a difference to the machine. And quantity calculus isn't a precisely defined, perfectly consistent system with no edge cases. It grew up in the messy real world. The act of implementing it in software dredges up those imperfections, and forces us to confront them. So: is the thing we read from a thermometer "really" a quantity or "really" a point? (And are there "really" points?) I think asking this kind of question is going to mislead and misguide us. What we're really doing is trying to construct some system which is simultaneously:
If we accurately express our problem --- and, keep in mind that imperfections are guaranteed by the nature of the beast --- then we maximize our chance to deliver the best solution possible. |
Beta Was this translation helpful? Give feedback.
-
I'm trying to get you to the realization that you have shot yourself in the foot by adopting the convoluted system of affine space. You yourself that have written this library don't know how to use it. People complain that it is too complicated, because it is. And at this rate I have a better chance of starting from scratch and getting a units library standardized before you do. |
Beta Was this translation helpful? Give feedback.
-
And that is perfectly fine. We never claimed that we wanted to model everything in the library's framework. We have to provide what is expected by the majority, and this includes temperatures and potentially also logarithmic units. We will never be able to provide automated conversions between things like the currency exchange or other time-point-sensitive cases that you mentioned, simply because the framework does not have enough data to do the conversion for you. But it does not mean it should not allow you to model some parts of it in a safe way. Please see our currency example https://github.com/mpusz/mp-units/blob/master/example/currency.cpp where we are able to define and successfully use different currencies in the same program in a type-safe say. The user has to provide custom conversion functions for such cases, though. Maybe, you could model ECEF and ECI in the same way? |
Beta Was this translation helpful? Give feedback.
-
Even if you will be able to design a library in such a way that it will account for offset and logarithmic units in a way you describe, you will still need two separate abstractions to specify when you are talking about points or vectors. It is needed to remove the ambiguity for temperatures so people do not make mistakes. It is also needed to prevent safety issues where you accidentally add temperatures, timestamps, prices, altitudes, etc. People want to model this as well. And yes, people want to model temperature differences in oC or oF as well and they will not be happy with oC and Rankine as an alternative, because plenty of them have even never heard about those. |
Beta Was this translation helpful? Give feedback.
-
I will do you one better. I will redo you a full implementation here: https://github.com/tmiguelf/unit |
Beta Was this translation helpful? Give feedback.
-
Here's another "meta-comment": I wanted to call out and praise some of @tmiguelf's points that haven't really been acknowledged yet. The nature of a technical discussion is to focus on points of disagreement, because those are the places where the outstanding work is. This can produce a tone of conversation that is biased and misleading, in that it can come across as far more negative and contentious than it really is. In that spirit, here are some really great points I'd like to explicitly affirm. We are fighting cognitive biasWhen we've put a lot of thought or effort into something, the human tendency is to identify strongly with that work. This biases us to inappropriately dismiss criticism of the work, because we can experience it as criticism of the self. Because we're trying to deliver the best product here, it's important to be extra-conscious of this effect, and for each of us individually to fight against it. Quantity point adds complexityThe "quantity point" solution --- which, by the way, Au and mp-units independently arrived at --- is there for a compelling reason. There are at least two distinct kinds of things that people might mean by, say, "2 degrees Celsius", and this was the best way we could think of at the time to distinguish them in code. However, most pen-and-paper use cases do not make rigorous distinction between "quantity" and "point" types. Humans can pick up on subtle clues from the context to determine which operations are valid. Thus, most users will probably also try to express their use cases in this simple manner. If we could satisfy them without introducing an extra type, while still avoiding opportunities for grievous error, that'd be great! Note that there's recent precedent for this kind of change in the library, too. mp-units used to have even more abstractions: "quantity kind" and "quantity point kind" (or was it "quantity kind point"? 😅). The brilliant v2 redesign eliminated the need for these types, and their absence tremendously improved the library. If we really can get rid of quantity point (without an unacceptable loss of usability), I expect that would be a similarly satisfying improvement. |
Beta Was this translation helpful? Give feedback.
-
Hi everyone,
Thank you very much for letting me participate in the discussion, and I get to learn more about the concerns surrounding the objections on how units are handled.
Some of my takeaways were:
I did not realize this at the time, but this last one is quite significant.
I would like to separate this into 3 different topics:
• What insight does logarithmic units brings and why you should pay close attention to it, and how it relates to the problem of oC
• The ability to cover all potential use cases.
• What’s the consequences of those 2 things on the overall goal of fixing the ABI
Insight of logarithmic units
I think this is one of those rare situations were making things much more complicated makes it easier to understand. Since it is a problem that I haven’t yet tackled, I went ahead and tried to think of how I would implement this myself and what you would need to make it work.
Let’s put ourselves in the shoes of a user who wants to add their own unit system into the library, for example a “smoot” (https://en.wikipedia.org/wiki/Smoot), I want to add a smoot as a unit of length.
What do I mean when I say that the Harvard Bridge is “364.4smoot”? We have 2 components:
• A radical (i.e. the number 364.4) that affects the unit. R
• A unit, a placeholder object, a reference object that describes the property we want to measure against. I.e. In this case a length equal to the Heigh of Oliver R. Smoot. U
And the relationship between these 2 properties is “multiplicative”. R×U
When we say that something is “2smoot” what it actually means is “get whatever a smooth is and join 2 of those”.
From this we can define a set of arithmetic properties:
• Addition: 5smoot + 3smoot (or more generically a×U + b×U), which is only solvable because of the distributive law
A× (B + C ) = A×B + A×C
ie. a×U + b×U = (a+b)×U
i.e. 5smoot + 3smoot = 5×smoot + 3×smoot = (5+3)×smoot = 8smoot
• Subtraction: which is also done via the distributive law
i.e. 5smoot - 3smoot = 5×smoot - 3×smoot = (5-3) ×smoot = 2smoot
• Multiplication by a scalar: 2×5smoot (or more generically a×(b×U)) which is solvable using the associative law
A×(B×C ) = (A×B)×C
I.e. 2×5smoot = 2×(5smoot) = (2×5)smoot = 10smoot
• Division by scalar: which is solvable by a variant of the associative law considering the division as a reciprocal of multiplication
I.e. 5smoot / 2 = (1/2)×(5×smoot) = ((1/2)×5)×smoot = 2.5smoot
• Conversion: if 1smoot=1.702m, then by using substitution
7smoot = 7×(1smoot) = 7×(1.702×m) = (7×1.702)×m = 11.914m
• Squaring, rooting, powers in general: (5smoot)^2 (or more generically (a×U)^b), which is solvable by using the distributive law for powers
(A×B)^C=(A^C) ×(B^C)
ie. (5smoot)^2 = (5×smoot)^2 = (5^2)×(smoot^2) = 25smoot^2
I’m not going to comment on either or not fractional or irrational powers of units are physically meaningful, those cursed things exist and the math doesn’t care.
• Multiply with other multiplicative units: 5smoot × 6N (or more generically (a×U) × b×V)), which is solved by using the commutative and associative rules
A×B = B×A
(A×B)×(C×D) = A×B×C×D = A×C×B×D = (A×C)×(B×D)
i.e. 5smoot × 6N = 5×smoot × 6×N = 5×6×smoot×N = (5×6)×(smoot×N) = 30Nsmoot
This also explains why certain operations aren’t allowed, for example 5smoot + 6N is not valid because there’s no conversion between a smoot and a Newton, you can’t apply any of the mathematical properties (distributive, associate, etc) in order to reduce the expression to 1 radical and a modified unit set.
I believe this to be uncontroversial, everyone should recognize how this works. Let’s apply the same reasoning to logarithmic units, how do they work?
Now, how does this work for logarithmic units?
Let’s use decibel as an example, now there are multiple interpretations of what a decibel means, there is the notion of decibel as used in attenuation that means one thing, but there’s also the notion of decibel that can be more generally applied as a modifier for the magnitude of units of something. It is the later that I will be using (please follow along https://en.wikipedia.org/wiki/Decibel)
Take for example dbV (decibel-Volt), what does 5dbV mean?
It means is a difference of potential T such that 10log_10(T/V_0) = 5, where V_0 = 1V.
The V_0 is important as it serves as reference point to measure the unit against, but also a requirement to be able to compute the radical, as T/V_0 would cancel the units portion of the expression leaving only the radicals allowing the logarithm to be resolved. If the units were not canceled in the expression, you couldn’t resolve the logarithm and extract a radical.
What we learn here is that:
• dbV is a unit of differential of potential just like a voltage is
• you can convert dbV to V by the following expression f(x) = 10^(x/10)
• the relationship is not multiplicative. Doubling the radical does not mean that you have twice as much difference in potential, but ×10 larger.
Logarithms have the property of transforming powers into multiplications, multiplications into additions, and additions into as convoluted mess we haven’t given it a name for. I.e.
log(A^B) =Blog(A)
log(A×B) = log(A) + log(B)
or reciprocally
e^(A+B) = e^A×e^B
(e^A)^B = e^(A×B)
From this our arithmetic rules work like this:
• Multiplication by scalar: 3×5dbV which is solved by the radical addition rule
10log_10(A×T) = 10log_10(A) + 10log_10(T)
3×(5dbV) = (10log_10(3)+5)dbV = 9.77121dbV
• Powers: (5dbV)^2 are solvable by the radical multiplication rule
log (T^A) = A×log_10(T)
(5dbV)^2 = (5×2)db(V^2)
• Conversion: ex. 5dbm to dbf is solvable by substituting the conversion factor and putting trough the radical addition rule
5dbm = (10log_10(3.28084) +5 )dbf
• Multiplication by other units: 5dbV×6dbA can be solved by adding the radicals
5dbV×6dbA = (5+6)dbW
• Addition: 5dbV + 6dbV, this one is kind of tricky as the easiest way to perform this calculation is to convert both this elements to V do the trivial addition and then convert it back to dbV
I don’t think mp-units is capable of handling that at the moment.
And here lies the crux of the problem, in order to handle units properly it is not sufficient to have a radical and a relationship between different unit variants, you also need to take into account the relationship between the radical and the unit, and this can be an arbitrary function, and this has an implication in terms of how the arithmetic is implemented.
For the case of lengths, the relationship of the radical to the metric is one of simple multiplication f(x)=ax, for the case of logarithmic units the relationship is exponential f(x)=a.e^(b.x). But this can be an arbitrary function depending on how someone decides to define the unit. And unless you can’t integrate that into design (which I don’t see how at the moment) there’s 0 chance you will be able to support everything.
You are going to have to pick and choose what type of arithmetic relationships you are going to support in advance.
How does this relate to oC?
When you measure a temperature the relationship between the radical with the units is expressed by the following function f(x) = ax+b, you can’t add to oC by adding their radicals because
AoC + BoC actually means f(A)+f(B)= a.A+b +a.B+b = a.(A+B) +2.b
and an operation where the radicals are subtracted cannot resolve in the same unit because:
AoC – BoC = f(A)-f(B)= a.A+b - (a.B+b) = a.A+b - a.B - b = a.(A-B) which is not expressed in terms of f(x)
I.e. when we are talking about oC as an absolute temperature, it is categorically not the same thing as oC when we are talking about a difference of temperatures, it is just extremely unfortunate that people give it the exact same name.
It is a similar confusion between pound and pound-force, people just call both of those things’ “pounds”, and inadvertently convert a mass into a force, or in oC case convert a temperature with a temperature with an offset.
To hammer in this point let me force the exact same problem into another metric, let’s define a smetre to be the number of meters above the length of a smoot.
If Greg is 0.1smetre (=1.802m) and George is 0.3(=2.002m) smetre what is the difference in height?
One would be tempted to just subtract the radicals and keep the units i.e. (0.3-.1)smetre = 0.2smetre; but it should be obvious that this result is erroneous as 0.2smetre =1.802m when the actual distance is 0.2m = -1.502smetre.
The problem here is that 0.3smetre - 0.1smetre is not the same as (0.3-0.1)smetre because the distributive property does not apply to a smetre. But it is for sure 0.2m.
What happens is that when you decide to subtract to temperatures expressed in oC and decide that it is only sufficient to subtract the radicals is that there is an hidden conversion of units that occurs, they are two different units that just happen to be named exactly the same thing. The problem is not affine spaces, the problem is that the arithmetic is different.
This is a problem for temperature, this is a problem for logarithmic units, this maybe a problem for other units that you haven’t even heard of.
On the ability of being able to convert between all use cases
You just won’t. And I would like to start with some use cases.
• Let’s say that I have a set of coordinates in ECEF (https://en.wikipedia.org/wiki/Earth-centered,_Earth-fixed_coordinate_system) which appears in applications like GPS, but what I want to do is astronomy and perhaps what I would like to have is my coordinates in ECI (https://en.wikipedia.org/wiki/Earth-centered_inertial). Now we do have the concept of a quantity_point, one would be tempted to define the coordinates in terms of quantity_points, but the problem is these coordinates systems are rotating relatively to one another.
In order to be able convert one coordinate into another, you don’t only need to consider the full 3D vector, you also need to account for the exact date in which the conversion needs to take place, which is complicated by the fact that the rotation of the earth is not constant and needs to be corrected for by physical observations.
• Let’s consider the case of airport altitudes, which are generally described in terms of “altitude above mean sea level”. The problem is airports are generally not above the sea, even if they were the sea level changes so that wouldn’t help you. The reason why altitude is important is so that airplanes can use their instruments in order to figure out how high they are relative to the runway, but the airplane can’t measure the altitude above mean sea level either. What they can do is measure pressure and using the ISA model of atmospheric pressure they can estimate their altitude, this is not exact by the way. But “measured” altitude in this way is going to depend on the weather, this is known, and before an aircraft some in for landing they receive a barometric correction that they have to input into their altimeter such that the altimeter indicates the “runway height” on standing on the runway.
Now you could pay a surveyor to measure things across the country from a well-known location in order to get you the runway height with some dubious uncertainty in the measurement. Or you could just take an history of pressure readings on site, average them out, plug into the ISA equation and call it a day, you are going to have to send an altimeter correction anyway.
Runway heights measured in this way, nobody knows how to convert it to a standard like WGS86 (https://en.wikipedia.org/wiki/World_Geodetic_System) it was dependent on the weather.
You won’t be able to convert this quantity_point to anything.
• There are navigation applications in robotics that use localized radio beacons for position, they work on a similar principle as GPS except the beacons can just be planted on a field, you are not trying to map the entire world, just some area with a known relative position to the beacons. But where those bacons are in relation to GPS coordinates is unknown, it doesn’t matter, it doesn’t need to know, or the relative position to the beacons matters. You will also need quantity points for these.
The point of these examples so far is to illustrate that it might make sense to define “families” of quantity points that are unconvertible to each other, and that multiple ones can be found within the same software, and the number of those are application specific (you can’t cover them all).
• Consider also the problem of empirical formulas, the fact that they exist. A simple example to understand would be ones like those used in the Richter-scale (https://en.wikipedia.org/wiki/Richter_scale), however they show up in places where the science is complicated, from drag in turbulent condition for specific profiles, to manufacturing cost estimations based on certain dimensions of a part. They are empirical fits in nature, they make absolutely no damn sense from a dimensional analysis perspective, the whole thing can be irrational non-linear, it is full of magic numbers that only work if and only if you use very specific units (you want to use other units you need different magic numbers). But somehow you plug in the numbers, and it more or less aligns with empirical data.
On this last one, you will never be able to provide a set a functions, integrated with a unit system that will be able to workout the right result, the whole process is just cursed. In these cases, the only option you have, is to grab the naked numbers, plug them in to do the math blindly, and manually fix the units.
Hopefully they are rare in use enough so the users can work these out by themselves, they will need the option of being handed in a gun so that they can try and shoot between their toes and hopefully it will be alright.
The point is, you won’t be able to cover all use cases. Pick a set that is broad enough and useful enough for the majority of cases, and say that’s it, the vast majority of cases is good enough.
The consequences of these analysis when it comes to ABI
You are not going to be able to support every use case.
You can do a lot of work to accommodate almost everything, but you are essentially fighting with the future, something can always eventually come up that won’t fit in the cookie cutter format you have chosen but that might be nice to integrate.
The way I see it, ABI breakage is not a deal breaker as long as it doesn’t happen often.
If the standard committee is more concerned with ABI not changing, perhaps you should consider the option of not making it part of the standard library. There’s nothing stopping anybody from using libraries. Being just a library, you can just break ABI whenever you want, all the users have to do is recompile, and maybe just some pieces of incompatible syntax.
The standard itself just defines what a library should have, not how it should be implemented, but realistically of such a proposal were to be accepted the specific implementation in practice will be yours, because it is quite complicated, it is already there and it is very easy to copy.
Perhaps keeping it as a library and not standardize it might be a better option?
Plus, it won’t upset people like me who would want to use a units system without having an affine space system that only makes it complicated, and I would like to work better with a different set of easier (for me) to use quirks.
This is just my 2cents.
Beta Was this translation helpful? Give feedback.
All reactions