[Units] Units in unit tests
Hello all,
please excuse the weird subject line. I have just introduced boost units as
length quantity for vectors into my project here.
What previously was:
typedef boost::qvm::vec
On 8/05/2017 02:08, Stephan Menzel wrote:
I have lots of lines like:
vec3 v = get_some_value();
and then I test the individual component values like this: BOOST_CHECK_CLOSE(X(v), 42.0, 0.001); // check for length of 42 meters
Now this would have to be rewritten to:
BOOST_CHECK_CLOSE(X(v).value(), 42.0, 0.001);
But doing this, I imply the length is in meters, right? Doesn't that defeat the purpose a little? I feel this would be better:
BOOST_CHECK_CLOSE(X(v), 42.0 * meters, 0.001);
but the Macro won't accept this as this is not a floating point type anymore. Does anybody have some hint as to how this is best addressed while still have maximum readability?
I don't know if there is a better way to do this within the confines of Boost.Test itself (perhaps making a custom macro, or extending what the macro already does in some way), but there *is* a better way to get basic values out of unit quantities rather than using .value(). Instead of: BOOST_CHECK_CLOSE(X(v).value(), 42.0, 0.001); Try: BOOST_CHECK_CLOSE(X(v) / meters, 42.0, 0.001); (You might also need an explicit static_cast<double>. If so, you might want to wrap this whole thing in a helper method to reduce typing.) This explicitly specifies what unit and scale you want the comparison to be performed in -- and you can for example request a comparison in millimeters or inches if you use the appropriate definitions. And it won't compile if you use the wrong dimension -- eg. if you try to extract seconds from a length measurement.
Hello Gavin, thanks for your response. On Mon, May 8, 2017 at 4:17 AM, Gavin Lambert via Boost-users < boost-users@lists.boost.org> wrote:
I don't know if there is a better way to do this within the confines of Boost.Test itself (perhaps making a custom macro, or extending what the macro already does in some way),
I was suspecting this, just wanted to clarify. I guess I will create my own wrappers then.
but there *is* a better way to get basic values out of unit quantities rather than using .value().
Instead of:
BOOST_CHECK_CLOSE(X(v).value(), 42.0, 0.001);
Try:
BOOST_CHECK_CLOSE(X(v) / meters, 42.0, 0.001);
(You might also need an explicit static_cast<double>. If so, you might want to wrap this whole thing in a helper method to reduce typing.)
OK, this is a bit of surprise. This "X(v) / meters" obviously means "I want the value in meters"? Actually I spent quite some time trying to figure that exact thing out and I just couldn't find it in the docs. I have just tried it and it works. Great, that's at least a way to make things explicit and helps. Thanks, Stephan
AMDG On 05/08/2017 01:11 AM, Stephan Menzel via Boost-users wrote:
On Mon, May 8, 2017 at 4:17 AM, Gavin Lambert via Boost-users < boost-users@lists.boost.org> wrote:
Try:
BOOST_CHECK_CLOSE(X(v) / meters, 42.0, 0.001);
(You might also need an explicit static_cast<double>. If so, you might want to wrap this whole thing in a helper method to reduce typing.)
OK, this is a bit of surprise. This "X(v) / meters" obviously means "I want the value in meters"? Actually I spent quite some time trying to figure that exact thing out and I just couldn't find it in the docs. I have just tried it and it works.
The meaning is literally division. (1.0 * meters) / meters = 1.0 If the expression exactly cancels out all units, then the result is dimensionless and can be implicitly converted to a double.
Great, that's at least a way to make things explicit and helps.
In Christ, Steven Watanabe
Hello Steven, thanks for your great work on Units! On Mon, May 8, 2017 at 3:11 PM, Steven Watanabe via Boost-users < boost-users@lists.boost.org> wrote:
The meaning is literally division. (1.0 * meters) / meters = 1.0 If the expression exactly cancels out all units, then the result is dimensionless and can be implicitly converted to a double.
OK, I see. From my perspective, having never used Units this was not quite
intuitive if you don't mind me say so. If you would allow me to get a
little off topic....
My reason behind switching to units was that I wanted to get rid of
implicit assumptions about what unit a quantity is in. I am in a client /
server environment and store such vectors coming from a client that uses
centimeters as all units. Now I expect further clients and want to be
prepared for them to use other units, say millimeters. By using Units I
intend to push that translation to the foremost interface of the system and
not translate anything behind that.
I have much appreciated the constructor of quantity and the fact that it
fails to compile without a unit to give meaning to a scalar. This is an
excellent design paradigm and will help eliminate bugs!
qlength q(42.0 * meters);
Nice.
My problem that led to the above misconception was, that I needed to
translate that back and forth to the client. From the client was quite
easy:
qlength q(4200.0 * centi*meters);
Looks good enough. But getting the value back in centimeters was not. I
tried:
double raw_value_to_send_back = q / centi*meters;
But this won't compile. So I looked into scaled units and typedefed this:
typedef boost::units::make_scaled_unit<
boost::units::si::length,
boost::units::scale<10, boost::units::static_rational<-2> > >::type
centimeters;
And now I can convert into centimers like this:
double raw_value_to_send_back = quantity
AMDG On 05/08/2017 07:30 AM, Stephan Menzel via Boost-users wrote:
Hello Steven,
thanks for your great work on Units!
On Mon, May 8, 2017 at 3:11 PM, Steven Watanabe via Boost-users < boost-users@lists.boost.org> wrote:
The meaning is literally division. (1.0 * meters) / meters = 1.0 If the expression exactly cancels out all units, then the result is dimensionless and can be implicitly converted to a double.
OK, I see. From my perspective, having never used Units this was not quite intuitive if you don't mind me say so. If you would allow me to get a little off topic....
This trick wasn't really a part of the library design. We originally intended that the primary way to access the raw value would be though q.value() or quantity_cast<double>(q). Using q / meters falls out naturally from the definition of division, though.
<snip> Looks good enough. But getting the value back in centimeters was not. I tried:
double raw_value_to_send_back = q / centi*meters;
But this won't compile. So I looked into scaled units and typedefed this:
typedef boost::units::make_scaled_unit< boost::units::si::length, boost::units::scale<10, boost::units::static_rational<-2> > >::type centimeters;
And now I can convert into centimers like this:
double raw_value_to_send_back = quantity
(n_value).value(); But still, I'm not sure I am using it as intended.
Yes. Casting to centimeters and then extracting the value is one way to do this.
Is this the best and easiest way to handle such things or am I mistaken and q / centi*meters really is supposed to work?
q / centi*meters is parsed as (q/centi)*meters, which
is not what you intend. Ideally, static_cast<double>(q/(centi*meters))
would work, but implementing that requires C++11 (explicit
conversion operators) and Units was originally written in 2006.
static_cast
participants (3)
-
Gavin Lambert
-
Stephan Menzel
-
Steven Watanabe