
I am using Boost.Units to try and compute the number of samples in a time interval, given the sample rate. Given this code: typedef make_scaled_unit<si::frequency, scale<10, static_rational<3> >
::type kilohertz_unit; typedef make_scaled_unit<si::time, scale<10, static_rational<-6> > >::type microseconds_unit;
<code> template <typename T=unsigned> using Kilohertz = quantity<kilohertz_unit,T>; template <typename T=unsigned> using Microseconds = quantity<microseconds_unit,T>; // Using boost::rational as the value type neatly avoids overflows Kilohertz<rational<unsigned>> sample_rate(125*si::kilo*si::hertz); Microseconds<rational<unsigned>> duration(10*si::seconds); auto total = sample_rate*duration; </code> Now, when I cout these values, I see that everything is technically the correct. The problem is that total is a dimensionless quantity which is scaled----it's 1,250,000,000, when I expect 1,250,000, and it displays as "1250000000 m", where m is "milli", not "meters". What is the correct way to un-scale dimensionless quantities? I tried this: quantity<si::dimensionless,rational<unsigned>> unscaled(total); However, unscaled still has the same value. I also tried typedef make_scaled_unit<si::dimensionless, scale<10, static_rational<0> >
::type dimensionless_unit; quantity<dimensionless_unit,rational<unsigned>> unscaled(total);
but this time, unscaled came out zero. Any suggestions?

AMDG On 02/14/2014 04:06 PM, Lindley French wrote:
<snip> Now, when I cout these values, I see that everything is technically the correct. The problem is that total is a dimensionless quantity which is scaled----it's 1,250,000,000, when I expect 1,250,000, and it displays as "1250000000 m", where m is "milli", not "meters".
What is the correct way to un-scale dimensionless quantities? I tried this: quantity<si::dimensionless,rational<unsigned>> unscaled(total);
However, unscaled still has the same value.
The result comes out as zero for me.
I also tried typedef make_scaled_unit<si::dimensionless, scale<10, static_rational<0> >
::type dimensionless_unit; quantity<dimensionless_unit,rational<unsigned>> unscaled(total);
but this time, unscaled came out zero.
Any suggestions?
The reason it's zero comes down to: std::cout << rational<unsigned>(1250000000) * 0.001 << std::endl; // prints 0/1 Conversions involving rational do not work correctly, because rational does not support multiplication by double. In Christ, Steven Watanabe

I find it very surprising that the conversion would use floating point, since scaled units use static_rational. Are you certain that's how it works?
On Feb 14, 2014, at 8:27 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 02/14/2014 04:06 PM, Lindley French wrote: <snip> Now, when I cout these values, I see that everything is technically the correct. The problem is that total is a dimensionless quantity which is scaled----it's 1,250,000,000, when I expect 1,250,000, and it displays as "1250000000 m", where m is "milli", not "meters".
What is the correct way to un-scale dimensionless quantities? I tried this: quantity<si::dimensionless,rational<unsigned>> unscaled(total);
However, unscaled still has the same value.
The result comes out as zero for me.
I also tried typedef make_scaled_unit<si::dimensionless, scale<10, static_rational<0> >
::type dimensionless_unit; quantity<dimensionless_unit,rational<unsigned>> unscaled(total);
but this time, unscaled came out zero.
Any suggestions?
The reason it's zero comes down to:
std::cout << rational<unsigned>(1250000000) * 0.001 << std::endl; // prints 0/1
Conversions involving rational do not work correctly, because rational does not support multiplication by double.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

AMDG On 02/16/2014 11:08 AM, Lindley French wrote:
I find it very surprising that the conversion would use floating point, since scaled units use static_rational. Are you certain that's how it works?
Given that I wrote the code, yes I'm certain. The values can be too large to fit in an integer type (even long long). In Christ, Steven Watanabe

Hmm. Ideally, I'd love it if floating point conversions were only used when the value type is floating point; the rest of the time, an integer conversion or static assert if necessary could be used. But thanks for the insight into the current behavior.
On Feb 16, 2014, at 2:26 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 02/16/2014 11:08 AM, Lindley French wrote: I find it very surprising that the conversion would use floating point, since scaled units use static_rational. Are you certain that's how it works?
Given that I wrote the code, yes I'm certain. The values can be too large to fit in an integer type (even long long).
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

What's the best way to access the current scaling of a dimensionless value? Maybe I can back it out myself rather than relying on type conversion to do it. On Sun, Feb 16, 2014 at 6:28 PM, Lindley French <lindleyf@gmail.com> wrote:
Hmm. Ideally, I'd love it if floating point conversions were only used when the value type is floating point; the rest of the time, an integer conversion or static assert if necessary could be used. But thanks for the insight into the current behavior.
On Feb 16, 2014, at 2:26 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 02/16/2014 11:08 AM, Lindley French wrote: I find it very surprising that the conversion would use floating point, since scaled units use static_rational. Are you certain that's how it works?
Given that I wrote the code, yes I'm certain. The values can be too large to fit in an integer type (even long long).
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

For the life of me I can't figure out where the actual multiplication of the value occurs. Boost Units is very clever template magic, but I doubt anyone could maintain the thing without weeks of studying the design.... On Mon, Feb 17, 2014 at 9:48 AM, Lindley French <lindleyf@gmail.com> wrote:
What's the best way to access the current scaling of a dimensionless value? Maybe I can back it out myself rather than relying on type conversion to do it.
On Sun, Feb 16, 2014 at 6:28 PM, Lindley French <lindleyf@gmail.com>wrote:
Hmm. Ideally, I'd love it if floating point conversions were only used when the value type is floating point; the rest of the time, an integer conversion or static assert if necessary could be used. But thanks for the insight into the current behavior.
On Feb 16, 2014, at 2:26 PM, Steven Watanabe <watanabesj@gmail.com> wrote:
AMDG
On 02/16/2014 11:08 AM, Lindley French wrote: I find it very surprising that the conversion would use floating point, since scaled units use static_rational. Are you certain that's how it works?
Given that I wrote the code, yes I'm certain. The values can be too large to fit in an integer type (even long long).
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

AMDG On 02/17/2014 07:40 AM, Lindley French wrote:
For the life of me I can't figure out where the actual multiplication of the value occurs. Boost Units is very clever template magic, but I doubt anyone could maintain the thing without weeks of studying the design....
detail/conversion_impl.hpp:345 return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(u1, u2)))); This won't really help you because the result of conversion_factor returns a double. The scale is evaluated at detail/conversion_impl.hpp:448 return(conversion1::value() * (scale::value() / conversion2::value())); "scale" here is the result of get_scale_list/eval_scale_list. get_scale_list collects the scaling factors, eval_scale_list multiplies their ::value() together. Again, scale::value() returns a double, because the individual scale factors use double. (See scale.hpp)
On Mon, Feb 17, 2014 at 9:48 AM, Lindley French <lindleyf@gmail.com> wrote:
What's the best way to access the current scaling of a dimensionless value? Maybe I can back it out myself rather than relying on type conversion to do it.
There's a metafunction called get_scale_list, which returns an MPL sequence whose members contain static const long base = ...; typedef static_rational<...> exponent; It's not documented, so use it at your own risk. It's unlikely to change, but I make no guarantees. In Christ, Steven Watanabe

Solved it this way: si::dimensionless unscaled; double f = conversion_factor(u,unscaled); if (f < 1) { int64_t intf = static_cast<int64_t>(1.0/f + 0.5); return val.value()/intf; } else { int64_t intf = static_cast<int64_t>(f + 0.5); return val.value()*intf; } I can understand why double was chosen for scaling, but it doesn't "feel" right. Oh well, this will do for now. On Mon, Feb 17, 2014 at 11:17 AM, Steven Watanabe <watanabesj@gmail.com>wrote:
AMDG
On 02/17/2014 07:40 AM, Lindley French wrote:
For the life of me I can't figure out where the actual multiplication of the value occurs. Boost Units is very clever template magic, but I doubt anyone could maintain the thing without weeks of studying the design....
detail/conversion_impl.hpp:345
return(destination_type::from_value(static_cast<T2>(source.value() * conversion_factor(u1, u2))));
This won't really help you because the result of conversion_factor returns a double.
The scale is evaluated at detail/conversion_impl.hpp:448 return(conversion1::value() * (scale::value() / conversion2::value()));
"scale" here is the result of get_scale_list/eval_scale_list. get_scale_list collects the scaling factors, eval_scale_list multiplies their ::value() together.
Again, scale::value() returns a double, because the individual scale factors use double. (See scale.hpp)
On Mon, Feb 17, 2014 at 9:48 AM, Lindley French <lindleyf@gmail.com>
wrote:
What's the best way to access the current scaling of a dimensionless value? Maybe I can back it out myself rather than relying on type conversion to do it.
There's a metafunction called get_scale_list, which returns an MPL sequence whose members contain
static const long base = ...; typedef static_rational<...> exponent;
It's not documented, so use it at your own risk. It's unlikely to change, but I make no guarantees.
In Christ, Steven Watanabe
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On 18/02/2014 07:05, Quoth Lindley French:
I can understand why double was chosen for scaling, but it doesn't "feel" right. Oh well, this will do for now.
Bear in mind that scaling is used not just for SI prefixes but also for lb/kg conversions and similar. Double is probably the only way to go there.

Yes, I caught that subtlety and I understand it in that context. I just feel there should be some way to use Boost.Units---portions of it, anyway---in a context where exact math is required and floating point is therefore forbidden. On Mon, Feb 17, 2014 at 4:56 PM, Gavin Lambert <gavinl@compacsort.com>wrote:
On 18/02/2014 07:05, Quoth Lindley French:
I can understand why double was chosen for scaling, but it doesn't
"feel" right. Oh well, this will do for now.
Bear in mind that scaling is used not just for SI prefixes but also for lb/kg conversions and similar. Double is probably the only way to go there.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

I also think it's a design flaw to allow dimensionless units to have a scale factor, by the way. Ideally, that would be backed out automatically in the dimensionless case. On Mon, Feb 17, 2014 at 5:14 PM, Lindley French <lindleyf@gmail.com> wrote:
Yes, I caught that subtlety and I understand it in that context. I just feel there should be some way to use Boost.Units---portions of it, anyway---in a context where exact math is required and floating point is therefore forbidden.
On Mon, Feb 17, 2014 at 4:56 PM, Gavin Lambert <gavinl@compacsort.com>wrote:
On 18/02/2014 07:05, Quoth Lindley French:
I can understand why double was chosen for scaling, but it doesn't
"feel" right. Oh well, this will do for now.
Bear in mind that scaling is used not just for SI prefixes but also for lb/kg conversions and similar. Double is probably the only way to go there.
_______________________________________________ Boost-users mailing list Boost-users@lists.boost.org http://lists.boost.org/mailman/listinfo.cgi/boost-users

On 18/02/2014 11:18, Quoth Lindley French:
I also think it's a design flaw to allow dimensionless units to have a scale factor, by the way. Ideally, that would be backed out automatically in the dimensionless case.
I must admit that one can be quite annoying. There's a default conversion between an unscaled dimensionless quantity and the value type of the quantity but this is not valid for scaled dimensionless quantities. There was a thread about this a little while ago. It's not really a problem if you're doing all calculations using Boost.Units quantities and then simply printing the result, but it can bite you if you want to pass that as a raw value to some external API (which is probably the more common case in real-world code). I think the "right way" to do it (according to Boost.Units logic) is to define a system that has your target unit as a base unit, such that when you move the unit from one system to another it automatically rescales it to become the "real" value that you actually want, and you can get an unscaled dimensionless value out of it. It's a little annoying, but it's not actually all that much code. (Though as Steven said this won't help in your case because rescaling requires doubles, and rational<> doesn't support that.)

On 18/02/2014 11:14, Quoth Lindley French:
Bear in mind that scaling is used not just for SI prefixes but also for lb/kg conversions and similar. Double is probably the only way to go there.
Yes, I caught that subtlety and I understand it in that context. I just feel there should be some way to use Boost.Units---portions of it, anyway---in a context where exact math is required and floating point is therefore forbidden.
I don't disagree (and it might theoretically be possible, when the units involved only use rational scaling and not actual floating-point conversion factors, and when scaling is not too large). But I think the current implementation is fairly tightly wedded to floating point internally, and it might be tricky to break that link.
participants (3)
-
Gavin Lambert
-
Lindley French
-
Steven Watanabe