mp-units icon indicating copy to clipboard operation
mp-units copied to clipboard

Transfer rate in bits per second

Open AlanDaniels101 opened this issue 2 years ago • 6 comments

Hello,

Overall the library looks really cool and we are considering adopting it in our org.

Would it be possible to add transfer rate options in bits per second instead of bytes? Network bandwidth uses bits as a convention. It would probably even be better for the formatter to use bps (Mbps, Gbps, etc, instead of b / s or B / s).

Also, the default formatting for these cases seems undesirable: fmt::format("Bandwidth: {}", 2'000'000 * units::isq::iec80000::references::B / (1 * units::isq::si::references::us)) Bandwidth: 2000000 MB/s (it's a bit strange why using microseconds makes it print MB/s, and milliseconds would make kB/s and seconds B/s)

fmt::format("Bandwidth: {}", 2'000'000 * units::isq::iec80000::references::B / (1 * units::isq::si::references::min)) Bandwidth: 2000000 [1/6 × 10⁻¹] B/s Maybe this is specific to my environment..

fmt::format("Bandwidth: {}", 2'000'000 * units::isq::iec80000::references::bit / (1 * units::isq::si::references::s)) Bandwidth: 2000000 [1/8] B/s

Thanks!

AlanDaniels101 avatar Oct 06 '21 03:10 AlanDaniels101

Hi, first of all, thanks for the interest in the library and I am really happy that you find it cool 😉

transfer_rate in bits is a no-go as IEC8000 defines this only in bytes. However, we can add a new quantity dimension called bit_rate which according to IEC8000 is defined in bits per second. The only problem will be with a downcasting facility as both dimensions will have the same physical sense and will differ only with units. So the second one should just be an alias of the first one (not a new dimension). I will try to add it next week (this week I am too busy, sorry). You can also try to do it by yourself and provide a PR. See modulation_rate for an example of how to do it.

Regarding your other question about printing units. mp-units, and probably most other libraries, cannot print any unit. It prints only those that are predefined by the users. If you are interested in the output in us you should define such a unit explicitly. Otherwise, the library will do its best which means it defers to the dimension's coherent unit or its predefined prefixes (if available).

In the first case, the ratio of B/us is the same as MB/s. Trying to define a new unit of B/us will make the downcasting facility fail at compile-time (as there cannot be two units for the same dimension with the same ratio). However, you can define an aliased unit and explicitly use it in your code. Such an alias unit will be printed out correctly.

Regarding two other cases, those are not predefined so are printed in fractions of a coherent unit which for this dimension is B/s. It should be fairly easy to add new unit definitions that will print what you expect.

Regarding your strange output, I am not able to reproduce it. See https://godbolt.org/z/fdETGqcqc. Does your console support Unicode? If not please consider using ASCII output.

BTW, it seems that I broke fmt in the Compiler Explorer lately. Will have to fix it when I have some time.

mpusz avatar Oct 06 '21 13:10 mpusz

Thanks for the quick response!

transfer_rate in bits is a no-go as IEC8000 defines this only in bytes. However, we can add a new quantity dimension called bit_rate which according to IEC8000 is defined in bits per second.

This seems desirable and bit_rate is a good name.

The only problem will be with a downcasting facility as both dimensions will have the same physical sense and will differ only with units. So the second one should just be an alias of the first one (not a new dimension).

On one hand, it's fine for the fundamental type to be bytes and to just support formatting output as bps. But it also seems like it might be good to have bits be the fundamental type to reduce division / fractional cases.

Regarding your other question about printing units. mp-units, and probably most other libraries, cannot print any unit. It prints only those that are predefined by the users. If you are interested in the output in us you should define such a unit explicitly. Otherwise, the library will do its best which means it defers to the dimension's coherent unit or its predefined prefixes (if available).

In the first case, the ratio of B/us is the same as MB/s. Trying to define a new unit of B/us will make the downcasting facility fail at compile-time (as there cannot be two units for the same dimension with the same ratio). However, you can define an aliased unit and explicitly use it in your code. Such an alias unit will be printed out correctly.

I definitely wouldn't want it to print B/us. I think it should always default to B/s. For formatting as MB/s, it would be good to specify that this format in particular is desired, or that X digits prior to the period and Y digits after the period are desired, and it would select the prefix accordingly, preferring the numerator dimension. Perhaps this would get complicated for highly dimensional units though.

AlanDaniels101 avatar Oct 06 '21 14:10 AlanDaniels101

I think it should always default to B/s.

In this particular case maybe it would be a valid solution, but the library is designed in such a way that if you divide 120 km with 2 h you will get 60 km/h rather than the corresponding value in m/s. In most cases, this feature is a way better solution (least surprise to the user, no narrowing conversions, as fast as double, ...).

In case you prefer a coherent unit instead, you need to make it explicit in the library. However please note that it might backfire:

std::cout << fmt::format("Bandwidth: {}", quantity_cast<isq::iec80000::byte_per_second>(2'000'000 * B / (1 * us)))

prints:

Bandwidth: -1454759936 B/s

To make it work you need to provide big enough representation type:

std::cout << fmt::format("Bandwidth: {}", quantity_cast<isq::iec80000::byte_per_second>(2'000'000LL * B / (1 * us)));

In the case of the default behavior, the user can better predict that an overflow may happen.

mpusz avatar Oct 06 '21 14:10 mpusz

That makes sense. I'm not sure I'm doing something wrong (and let me know if there's a better place for questions), but it doesn't seem to keep km/h for me: https://godbolt.org/z/8oE5efefq

Doing a quantity_cast to byte_per_second (or bit_per_second in the future) seems good.

It might be nice to have a "safe" alternate version that would not overflow silently.

AlanDaniels101 avatar Oct 07 '21 23:10 AlanDaniels101

It might be nice to have a "safe" alternate version that would not overflow silently.

You can opt into having it checked, like using boost::safe_int as a representation type.

JohelEGP avatar Oct 08 '21 00:10 JohelEGP

but it doesn't seem to keep km/h for me

@AlanDaniels101 it does not keep km/h because such a unit was never defined in your code. Add

#include <units/isq/si/speed.h>

with predefined speed quantity units and you will see the difference 😉

mpusz avatar Oct 08 '21 12:10 mpusz

Done in V2

mpusz avatar Jun 15 '23 07:06 mpusz