-
Notifications
You must be signed in to change notification settings - Fork 94
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
Provide support for non-negative quantities #468
Comments
We should probably provide some exceptions from the rules for engineering purposes. For example, speed is defined as a magnitude of velocity which implies that it is non-negative. For engineering purposes, speed probably should be defined as |
What does the library need to do, |
The check implementation part is easy. Just do the compile-time branch with |
I think I have an answer. Either we do nothing, For example, I wrap a width and a height in a Cartesian vector. It seems to me that ISO/IEC 80000 sometimes calls out special cases like this.
it seems to me that we actually want an interface that both applies Quantity_of<width> auto q = (entity1.pos.x - entity2.pos.x).non_negative(); when I require the result to be the width that is non-negative,
Others include quantity difference and quantity point pairs.
There may be a few others, but I don't remember. |
Sure, please note that subtracting width from height is a length that is not constrained by itself. ISQ defines only width, thickness, diameter, and radius to be non-negative. Additionally, probably quantities that are defined as magnitudes of vectors could be non-negative as well. However, subtracting width and width will give you width as a result, and we have to decide what to do with that... 😉
I actually never thought of that, but I am not sure if that is needed. The temporary result probably does not need constraints. The check has to be done in the width constructor if the value is non-negative anyway.
I am not sure if we should constrain some ISQ types to be used only for either |
I meant the vector values, which does the component-wise operation |
This is why I answered
I forgot that to mention that it might just be the case of a missing abstraction. |
Please note that Probably, you are abusing |
Yeah, I'm considering that. |
I would do something like: QUANTITY_SPEC(pos_x, isq::length);
QUANTITY_SPEC(pos_y, isq::length);
QUANTITY_SPEC(pos_z, isq::length); |
Yes, if we really want to subtract two widths measured by the caliper and we really need to subtract the bigger value from the smaller one we would probably need something like that: QuantityOf<isq::length> auto q = isq::length(width1) - isq::length(width2); which I think may have some sense in a "twisted" physical way 😜 |
I remember that we did discuss this before. |
The reason I haven't convinced myself of that |
My Cartesian vectors, represented with I think it's perfectly valid for a difference of widths to be negative. So if a quantity of width is supposed to be non-negative, what is the missing abstraction? |
The ISQ defines width as:
How can a length between two parallel lines be negative? I do not think it has anything to do with points here. If we subtract two widths, we actually do not subtract the widths but their lengths. That is why I think that the cast I mentioned above makes a lot of sense from the physical point of view. |
That's why this time I'm referring to a difference of widths, |
Maybe it'd make more sense if |
So yeah, as a generalization of |
I do not think that we miss something here. We might just misuse what we have. Notice that As I wrote before, width is something that you can measure with the caliper, and physically you can't measure negative widths, right? 😉 If we subtract a longer displacement from a shorter one and take a magnitude of it, it would not be a width in a physical sense. Let's forget about vectors for now and see the following: // measured with caliper
quantity<isq::diameter[mm]> outside_pipe_diameter = 20 * mm;
quantity<isq::diameter[mm]> inside_pipe_diameter = 16 * mm;
quantity<isq::thickness[mm]> pipe_wall = quantity_cast<isq::thickness>((outside_pipe_diameter - inside_pipe_diameter) / 2);
std::cout << "Thickness of the pipe wall: " << pipe_wall << "\n"; If I accidentally subtract the outside diameter from the inside one I will get a negative value which does not make sense and the entire purpose of this Issue is to help find such problems (unfortunately only at runtime). |
Now, let's come back to vectors. If we deal with vectors, we should use Having those, we can subtract them, take the magnitude of the result, and cast it to The above is probably not a correct approach as well. So what we should do is the following: quantity<isq::displacement[mm], la_vector> outside_pipe_diameter = {2, 3, 4} * mm;
quantity<isq::displacement[mm], la_vector> inside_pipe_diameter = {1, 2, 3} * mm;
quantity<isq::thickness[mm]> pipe_wall =
quantity_cast<isq::thickness>(isq::diameter(magnitude(outside_pipe_diameter)) -
isq::diameter(magnitude(inside_pipe_diameter)) / 2);
std::cout << "Thickness of the pipe wall: " << pipe_wall << "\n"; We have #463 opened to discuss how to handle vector quantities in the library correctly. |
Rather than vector space, it seems like I meant more specifically affine space.
|
OK, I was confused because you mentioned taking the magnitude of a vector several times. What does the magnitude of such a vector/difference quantity mean? |
Also, I think I was wrong in claiming that a negative width has no physical sense. For example, let's assume that we measure the width of brake pads in my car with a caliper today and after half a year. The second measurement will be smaller, which should give me the answer that the pads shrunk by this amount. It is still a quantity of width and its value probably should be negative. |
Does it mean that in case we will add support for non-negative quantities they should actually apply only to the values in the |
If I'm struggling more finding something that you can't measure with
I don't think so, since you can have negative points. |
I am not sure if I understand what you meant here. First, you say that a vector can't represent negative quantities and then you say that is obvious 😉
What does a negative point of width mean? |
Depends on your origin, I guess. |
I agree with ISQ; there are no negative widths. Then what do Do note that ISO/IEC 80000 already defines "quantities" that are points. [ Note: [ Note:
This is why I'm contemplating using a I'm still rewriting things to use |
I wouldn't like to use the term Also, |
ISQ is not that specific, but if some life-critical aviation application needs to distinguish those, it can always derive its own quantity kinds from |
This is what I've settled with for now: https://cpp2.godbolt.org/z/sWj1K5rc8. With that, I specify arguments and members that are magnitudes. I still need to use So far, I've been able to rely on the implicit conversion of |
#428, and #353 (comment) in particular, |
No, sorry, that not entirely right. |
This is also doubtful. |
I wouldn't recommend using unsigned type for that, but a custom wrapper for representation type could do the work. However, I do not see how it is different than adding proper checks to the constructor and assignment of |
IIUC, the consensus on yesterday's meeting was that, for non-negative quantities, I have been thinking that, indeed, that should suffice. We also talked about being able to subtract quantities specified as non-negative. I still view The convenience of generalized non-negative quantities is being able to catch math errors.
As an aside, I originally gave the example of frequency instead of height. |
More simply, |
I think it was @mpusz who said that we wouldn't be having this discussion if I'm going to suggest that the Now, a question of safety. The first one is the very constraining choice of all non-negative quantities always being contract-checked. The second one is to attempt to educate users. |
The more I think of it, the more I am convinced that negative speeds should indeed be velocities. A negative value is to represent a vector in the "backward" direction, right? 😉 However, I think that it should be perfectly fine to obtain speed by dividing i.e. height by time, and not always through a magnitude of position vector. Do we have any idea how to handle that? |
Height and altitude are the same quantities in ISQ and negative altitudes are perfectly fine. |
Yeah. |
But negative altitude is possible. Nearly all Netherlands apply here ;-) |
I do not think it is correct. For example, I think it would be perfectly fine to define: inline constexpr struct passenger_height : quantity_spec<isq::height, non_negative> {} passenger_height; |
Yeah. |
I would not like to increase the number of template parameters for a |
This is why we need a dedicated/custom quantity type for such use cases. See #468 (comment). |
If speed can't be negative, how do we represent changes in speed? |
Right. The same logic could be applied to I think that |
As you say, the same can be done for It might make sense to have a delta of a This is similar to force being a vector quantity, and the force normal a scalar quantity. |
So yeah, I think that
then we're set to be able to enable the safer default of It leaves the mouth a bit salty that the checks are done at runtime. But there's only so much safety that type-safety can buy you, |
Still working through my ideas about non-negative (as well as other constrained quantities) but finally made it through this whole thread in detail so wanted to leave a few notes. Earlier this year when discussing (DSP) level and power (i.e level^2) (both non-negative quantities) I initially thought that maybe the quantities should be allowed to be negative so you could do signed math on them and use just "non-negative" as an API precondition. I had some colleagues make some arguments in favor of these being explicitly non-negative quantities because if level were allowed to be negative then the relationship between level and power would not be isomorphic. Recently with doing various quantity/unit experiments I do think I agree with this but at the same time think being able to do signed math that could result in negative values with these quantities (thinking about ES.102: Use signed types for arithmetic). I think using a signed representation type with non-negative preconditions would violate that guideline. I'm still puzzling through ways to both follow this guideline and put preconditions on quantities that shouldn't be allowed to be negative. First some comments older comments:
I would agree that a "width" with this definition cannot be negative. At the same time it may be useful to be able to do math with widths that could result in negative values as intermediate values in a calculation as long as the final result is non-negative when it needs to be "used" similar to the benefits of signed container sizes and signed arguments to array subscripts: if you are doing math on indexes you want to do signed math that could go negative but this is okay as long as your final result is non-negative when used as a subscript.
I think we might be stuck with a runtime check. The only other solution I could think other than runtime checks would be to disallow subtraction but this would not help with multiplication/division which would still have a runtime precondition that the quantity is being scaled by a positive value. I guess thinking out loud, addition of a negative value would also need a precondition or not be allowed. Maybe we should not do math on non-negative quantities? This would seem to limiting I think.
I had thought about something like a this
I am curious to check out the safe-numerics stuff presented at CppCon this year because maybe there is something I'm missing but it seems like run-time checks are the best solution for this although of course doesn't provide 100% safety.
Reducing boilerplate was what made me first think about this but I later realized that my current approach with using non-negative representation types when creating a |
ISO 80000 explicitly specifies quantities that have to be non-negative (width, thickness, diameter, radius).
Some of the quantities are implicitly defined as non-negative. For example, "path length" is defined as
hypot(dx, dy, dz)
. Others are defined as the magnitude of a vector which also is always non-negative.Some quantities are also explicitly defined as signed (i.e. height), so they should not be treated as a
norm(position_vector)
.The text was updated successfully, but these errors were encountered: