-
Notifications
You must be signed in to change notification settings - Fork 91
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Should conversions from the raw numerical value to a dimensionless quantity with a unit one be allowed? #553
Comments
For reference, the SI Brochure says:
If it's desired, I think it should be explicit. |
And what about conversions back to the number? |
BTW, lack of implicit conversion to a static_assert(10 * km / (5 * km) == 2 * one);
static_assert(10 * km / (5 * km) + 1 * one == 3 * one); and I think it is the biggest motivation for such a change. Unless, we want to explicitly allow comparisons and arithmetics with pure numbers but still prevent conversions. |
It appears this library is targeting application developers. But if I'm not mistaken, a requirement to standardize is the code must generically interoperate with the rest of |
This actually is not the requirement of the standardization process.
Why dimensionless is special here? Why don't you need a My point here is that I do not think that the dimensionless quantities are not that special at all.
Regarding zero, please see the #487 (comment). |
Fair enough, but this is certainly a desiderata.
My context for the discussion is the Buckingham-π theorem, where nondimensionalization produces natural scales for the problem at hand. In this context, dimensionless numbers are special. Statements like "|x| ≪ 1" make sense for dimensionless numbers, but not for dimensioned, and this is reflected in how code is written. As another example, I think you would concede unif(0,1) random numbers are useful when the values being generated are dimensionless, but contextless generation of unif(0,1) would probably be a bug if the "1" had dimensions of m/s. |
Do you mean mp-units/src/core/include/mp-units/random.h Lines 110 to 112 in 2889658
|
So even if I use this file, I still have a problem that I cannot write generic code which works with both
And if I add the The second problem is that my users have to know that I'm using |
It is even worse, class templates do not work with UDL 😉 so including |
The type of the result of a calculation on two quantities Q<d1,v1> op Q<d2,v2> where the result is dimensionless should merely be the type of(v1() op v2()). No conversion required. I found this the simplest and best solution for my quan library and also my pqs library . A number is a pure mathematical construct, whereas a physical quantity is not. When you wish to find the ratio between two lengths the ratio is transformed to the pure math domain despite it originated from physical quantities, the satisfying and fundamental difference between maths and physics. |
Do you intend for this statement to apply to all dimensionless result types? Or merely to results that are dimensionless and unitless (i.e., the "unit one")? If the latter, I think it's a defensible design decision. (In fact, it's what Au currently does, although experience has persuaded me to move away from this in the future.) However, if you're proposing a raw numeric result type for all dimensionless results (such as "cm / m", which is equivalent to "percent"), then I would consider it a grave mistake. |
Let us avoid phrases designed to excite emotions. You want one thing, I and from your own comments in your link, your users expect another. Neither is a "grave mistake". We just want different things. The real problem is: mp-units doesn't provide the flexibility to mould the semantics. In fact the claim in mp-units to be able to represent different systems is not upheld in practise. It provides one system and uses that as the basis for the rest. PQS provides a set of concepts which allows customisation for a particular system, so In pqs the semantics of operations on quantities are customisable. If you want to return a dimensionless_with units entity and I want to return a number then the library allows us to customise it to do so. |
This is actually not true. mp-units is fully capable of providing various independent systems if needed. One such example can be The rest of the systems are defined on top of the SI because this is how they work in reality. But it does not prevent anyone from doing otherwise. |
I will have to look again, as I didn't look in a while, but if you cant change the semantics of operations ( so result type of op) then effectively you are limited to one system, since different systems will have different semantics. If that was not the case then there would be no reason to open this issue, since you create a system with your preferred semantics. |
I do not believe that it is true. The library framework should be independent of systems of units and quantities. The same operation (e.g., division) should always return the same interface no matter which system you use. Of course, one might decide to define the library in terms of concepts, as you did in PQS. But those should not behave differently for different systems. They may provide different features/behaviors for different user needs, though. My worry with such a solution is that we can end up with an explosion of many types having similar semantics mandated by concepts. This, in turn, will result in interoperability problems between those types and interfacing issues between different vendors. |
I can't follow what you are trying to say there. What do you mean by interface ? Let us try some code to agree on some common ground. assume we have 2 quantities and 2 concepts ...
The following must now hold for mp-units, quan, pqs ( can be done for std::chrono) and other similar libraries
We know very little about q1, q2, q3 so far but assuming the leeway of replacing the aliases names below for your own libraries names for these things, these are are the "interfaces" here
|
Quite right --- I unconditionally apologize, and will try to do better in the future. Besides the needlessly emotionally charged language, my main mistake was not explaining why I came to adopt my viewpoint. One good resource is this discussion page on dimensionless units. In particular, the last section explains the drawbacks of supporting implicit conversion between non-unity dimensionless numbers (such as percent) and the raw numeric types. The risks are more than just hypothetical, too: the nholthaus/units library has this behaviour, and it has led to fiendishly thorny problems such as nholthaus/units#328, nholthaus/units#276, and nholthaus/units#275. Of course, I don't think implicit conversions are exactly the same thing you're talking about: I think you're proposing that the library should simply produce a raw number from a computation whose result is dimensionless. (Let me know if I'm wrong.) This is what Au currently does for unitless only, although aurora-opensource/au#185 tracks our goal to remove even this, as we've already discussed. For other dimensionless units, I think the main difficulty is the choice between following your proposed policy exactly, and avoiding surprising and very lossy conversions. I don't think we can have both, unless I've missed something! For example: what should
The result type should be |
I do not think that having a separate concept for a dimensionless quantity is a good idea, especially when there is no subsumption relationship between them. For example,
I am not sure what this means? Do you mean things like SI and CGS? Those are separate systems (both defined in terms of SI), but their quantities can be compared. I can also imagine systems where units from even the same system might not be compatible (see https://github.com/mpusz/mp-units/blob/master/example/currency.cpp).
The above issue is the result of treating dimensionless quantities separately. This is on of many reasons that I prefer the approach used by mp-units.
In your previous message, you wrote, "if you can't change the semantics of operations ( so result type of op), then effectively you are limited to one system, since different systems will have different semantics." I thought that you meant that you want a design where dividing length/length in one system may provide a number but may yield a dimensionless quantity in another system. I don't think that the system of units being used should affect this. I may imagine two class templates (e.g., As I wrote this a long time ago in answer to your ideas about concepts, I think that one of the biggest problems is deciding what to return if we add two different quantity class templates for the same dimension (e.g., |
I will quote what I actually said here
EDIT : I should say the library should allow us to customise.... I haven't tried customising to return a dimensionless quantity with units in PQS yet |
Surely mp-units has a means to distinguish a dimensionless quantity from a dimensioned quantity? If not a concept, then a trait surely, but that is splitting hairs:
|
A number is a dimensionless quantity.
And this seems to be at the heart of this issue. You want to encapsulate a number in a dimensionless_quantity_with_units type, perhaps like pqs::scaled_value and sure that might be a useful optimisation, but the feedback you have in the LEWG, from @chiphogg's users, from myself, from others is that returning a dimensionless quantity with units is not intuitive, and so doesnt fulfill the "ease of use" requirement. So I would suggest allowing use of such a type , but as a default to do the simplest, most intuitive thing. For most of use the ratio of two lengths is a number, not a "dimensionless quantity type with a string of units". |
It depends on what we call a "quantity" here. In generic programming, you may expect that dividing two
None of that will work when a raw number is returned, which complicates all the generic programming logic as you need to do special cases in each such function. Also, at the very beginning of my journey with standardizing the library in the ISO Committee, I was warned that we should not repeat three
Those are considered serious issues by many experts, and I agree with them.
I think that people actually do not complain about returning such quantities. They complain that we can't call "legacy" functions taking a value with such a resulting type. This is why I created this Issue to discuss if we should consider making an exception here and allow such conversion, but only if the unit is |
Using functions would be preferable so allowing use of pod ...
|
That is actually funnier to me than you can ever know. :) Though again there is emotive language being used above, rather than rational argument ( "mistakes" -> design decisions, "serious issues" -> sub optimal etc) . But yes, std::chrono was rushed in without any proper discussion AFAICS. Its compile time units looked on the surface much like my old version of PQS but... FWIW pqs ( even in 2005) used binary_op<Q, op,Q>::type to provide a result type of an op https://github.com/kwikius/pqs/blob/master/src/include/pqs/bits/impl/binary_op_impl.hpp . This allows customisation for udts FWIW Pqs (even in 2005) used a ratio and exponent https://github.com/kwikius/pqs/blob/master/src/include/pqs/bits/conversion_factor_def.hpp , whereas the std::chrono authors believed that a std::ratio would hold all the range you would ever need :) std::chrono is in common use and I don't personally have a major issue with the explicit value constructor, nor have I heard others complain about it. It is an intuitive way to initialise from a number. There are problems I seem to remember that it assumes everything is a double. To be honest I don't really use it as I generally use the same functionality in my own quan library. |
This mp-units design decision is to me sub-optimal , for the reasons you yourself state ;) |
@mpusz : This is indeed a correct description of my particular problem-I only need |
@NAThompson, I plan to work on this in the next days. There are two ways to somehow address it:
We can't have both because it breaks In the second case, the following and similar would not work: (5. * km / (10 * km) + 0.1).in(percent) This is why I prefer the first solution. In any case, I plan to provide the other conversion as well. It will just be Please let me know your thoughts. |
My goal has always been generic interoperability with units so that I can check the dimensional consistency of my code while allowing my users to just use floats, not needing to add |
It is difficult for me to answer this question as I do not know your code. Can you provide a specific code snippets that do not work right now but that you would like to enable in the future? |
I may not fully understand your code, but it seems that the main issue you have right now is to make I think that with the proposed changes in point 1. above, both of those cases should work. |
Also, |
@NAThompson, it is done. You check the changes in the "Superpowers of the unit |
A few parties (including LEWG) were surprised that we have to write
42 * one
to assign a raw value to aquantity
. See also #497 (comment).This, of course, is consistent with the rest of the library and tries to prevent the cases where someone will initialize quantities measured in percentages or other dimensionless units from the raw value.
In 0.8.0, we had an exception for the dimensionless quantity of a unit
one
. Such quantity was implicitly convertible from a raw value. This was inconsistent with the handling of other units and increased the complexity of the design a bit, but it was user-friendly.Should we add a similar feature to the 2.0 framework?
Should the conversion happen implicitly or explicitly? Should we also provide a conversion from quantity to a numerical value in such cases?
The text was updated successfully, but these errors were encountered: