mpusz / mp-units

The quantities and units library for C++
https://mpusz.github.io/mp-units/
MIT License
1.06k stars 85 forks source link

Metric Prefixes for Degrees Celsius #604

Closed CrustyAuklet closed 1 month ago

CrustyAuklet commented 1 month ago

I've been happily using this library in some embedded systems for the past year or so and am now upgrading to the latest v2 version. One thing I am running into is the fact that prefixes are disabled on Celsius. I did some digging and found the commit docs: degree_Celsius confirmed to not have SI prefixes. Is there a source for this confirmation? I don't see any closed issues regarding it, and as far as I know it is uncommon, but not disallowed, to use metric prefixes with degree Celsius.

I do often see prefixes used with Celsius in software. It is very common in the various embedded scientific instruments I have worked on to allow an integer representation while maintaining the needed precision. I have also seen it in other APIs, for example the linux kernel uses millidegrees Celsius.

Maybe a link to the SI documentation to support this decision would be a good addition to the documentation, and some sort of example for interacting with APIs using millidegrees Celsius. Do I just use milliKelvin in new software and then manually add and subtract zeroth_degree_Celsius at all the API interactions? or is there a better way?

mpusz commented 1 month ago

Thanks for raising this issue. I was not aware that some software already uses prefixes for degrees Celsius.

ISO 80000-5: Thermodynamics explicitly states:

Prefixes are not allowed in combination with the unit °C.

So now we have a problem :wink: We can either be standard conformant or friendly to an established engineering practice. @chiphogg and @bernedom, do you have any ideas on how to proceed? Do you use prefixes for degree Celsius in your libraries?

mpusz commented 1 month ago

As a workaround, you can provide such a unit by yourself:

inline constexpr struct milli_degree_celsius final : named_unit<symbol_text{u8"m℃", "m`C"}, mag_ratio<1, 1000> * si::degree_Celsius> {} milli_degree_celsius;
inline constexpr auto mdeg_C = milli_degree_celsius;

See a full example here: https://godbolt.org/z/qzT3r1TG1.

chiphogg commented 1 month ago

I find the explicit prohibition surprising. It makes me wonder what the rationale was. Is it just because they don't know whether to write "m°C" or "°mC"? :sweat_smile:

We provide prefixes for Celsius and Fahrenheit in Au. It's pretty useful, and has never caused any problems as far as I'm aware.

mpusz commented 1 month ago

I don't know the rationale here, but it is officially prohibited by an international standard that we try to follow in our library. I think we should keep it as forbidden and discuss it at the nearest C++ Committee meeting in Wrocław.

CrustyAuklet commented 1 month ago

As a workaround, you can provide such a unit by yourself:

inline constexpr struct milli_degree_celsius final : named_unit<symbol_text{u8"m℃", "m`C"}, mag_ratio<1, 1000> * si::degree_Celsius> {} milli_degree_celsius;
inline constexpr auto mdeg_C = milli_degree_celsius;

See a full example here: https://godbolt.org/z/qzT3r1TG1.

Thank you for the example, I made an attempt but I was not working "low" enough and was running into the unit_can_be_prefixed trait.

ISO 80000-5: Thermodynamics explicitly states:

Prefixes are not allowed in combination with the unit °C. awesome, thanks! I really like having references like this in the documentation for the SDK I am writing.

mpusz commented 1 month ago

I've just provided a short info in the documentation on how to work around this limitation if needed.

chiphogg commented 1 month ago

From the new docs:

some projects are not aware of those limitations

Maybe, but we don't really know that they're not aware, because we haven't asked them. Just as we haven't asked to find the rationale for this explicit prohibition.

Maybe they're looking at alternative credible sources, such as this NIST page, which explicitly declares,

Prefix symbols may be used with the unit symbol ºC and prefix names may be used with the unit name “degree Celsius.” For example, 12 mºC (12 millidegrees Celsius) is acceptable.

Or maybe they've weighed that unexplained prohibition against the obvious usefulness of these prefixes, and decided to take this approach:

nick-fury-recognize

(Not saying it is a stupid decision, since we don't know the reasons --- just taking an excuse to post a Nick Fury gif. :slightly_smiling_face:)

Personally, I don't see any value in prohibiting applying any prefix to any unit. It's clear enough what it means. If end users find it useful enough to create a named unit which they call milli-degrees-celsius, it's not merely obnoxious to force them to reproduce the numerical value of that prefix, but it creates a new opportunity for error where none needs to exist.

Wouldn't it be satisfying to simply remove all of the unit_can_be_prefixed machinery from the library, both simplifying the code and making the library more useful? :slightly_smiling_face:

mpusz commented 1 month ago

Wouldn't it be satisfying to simply remove all of the unit_can_be_prefixed machinery from the library, both simplifying the code and making the library more useful? 🙂

Sure, we can consider doing this.

chiphogg commented 1 month ago

I guess if we end up keeping the prohibition, then for consistency's sake with the standard, we would also need to prevent prefixing any prefixed unit --- so, micro<kilo<grams>> and micro<kilograms> (not sure if I spelled it right for mp-units) should both be prevented.

(Note: not proposing that we do this, just something that occurred to me just now. I personally still think "just let users apply any prefix they ask for" is likely best.)

JohelEGP commented 1 month ago

That's already prevented, as is standard.

mpusz commented 1 month ago

Yes, the standard explicitly states that we are not allowed to prefix an already prefixed unit. This is not allowed in mp-units as well and I think that we should keep it.

mpusz commented 1 month ago

The question is if we should remove unit_can_be_prefixed trait, simplify the framework, and allow the user to prefix every unit.

mpusz commented 1 month ago

Even if we remove it, I still wouldn't like to provide predefined symbols for the prefixed versions of degree Celsius in the library. Users will need to define them by themselves.

mpusz commented 1 month ago

BTW, it is really strange that NIST explicitly names millidegrees Celsius while ISO 80000 explicitly forbids it.

chiphogg commented 1 month ago

I agree with basically everything you've just said.

Maybe omitting predefined prefixed units is how we honor ISO 80000, while letting users explicitly form them if desired is how we honor NIST. :slightly_smiling_face: