Skip to content
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

subtraction of dimensionless quantities produce surprising result #33

Open
correaa opened this issue Oct 5, 2018 · 2 comments
Open

Comments

@correaa
Copy link

correaa commented Oct 5, 2018

In a generic environment one needs to write generic function involving integer integrals.

template<class A, class B> auto f(A a, B b){return 1 - a/b;}

Feeding f(1.,2.) gives 0.5.

However if one feeds f(1.*si::meter, 2.*si::meter) insted one gets 1 and of type int.

This is probably because the dimensionless quantities are implicitly convertible to their value type, which is a good feature. But for some reason in this case this double is converted to an int before doing the subtraction. The second implicit conversion in seems to be very strong in the language and I don't see a way to solve this in the library (please don't make the conversion explicit! that creates many other problems.).

The only solution I found was to define a family of functions specialized for int.

namespace boost{
namespace units{
template<class S, class Y>
inline
quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>
operator-(int i,
    const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q2)
{
    typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type;
    return quantity_type::from_value(i - q2.value());
}
}}

The good news is that this is in principle only needed for int, the bad news is that one need to implement many functions, (int - dimlessQ), (dimlessQ - int), (int + dimlessQ), (dimlessQ + int), (int * dimlessQ), (dimlessQ * int), (int / dimlessQ), (dimlessQ / int).

I would say this is a bug, but that can be controversial. What it is not controversial is that it is surpring because even for totally dimensinless arguments it will not behave like a double.

Is there a workaround solution?

@correaa
Copy link
Author

correaa commented Oct 5, 2018

Digging a little further I realize that the problem is mainly with pre-subtraction and pre-addition int - dimlessQ and int + dimlessQ. At the moment, multiplication, division and post-addition and post-substraction gives correct result. However there still a glitch that is that dimlessQ + int and dimlessQ - int return a double (or the underlying type of dimlessQ) instead of dimlessQ, which I expect is the expected result.

So , in summary I think this is resolved by adding these operation to the boost units namespace:
(Perhaps the only extra case is for unsigned int, long, unsigned long, etc)

namespace boost{
namespace units{
#if 1
template<class S, class Y>
inline
quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>
operator-(int i,
    const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q2)
{
    typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type;
    return quantity_type::from_value(i - q2.value());
}
template<class S, class Y>
inline
quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>
operator-(
    const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q1, int i)
{
    typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type;
    return quantity_type::from_value(q1.value() - i);
}
template<class S, class Y>
inline
quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>
operator+(int i,
    const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q2)
{
    typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type;
    return quantity_type::from_value(i + q2.value());
}
template<class S, class Y>
inline
quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>
operator+(
    const quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S), Y>& q1, int i)
{
    typedef quantity<BOOST_UNITS_DIMENSIONLESS_UNIT(S),Y> quantity_type;
    return quantity_type::from_value(q1.value() + i);
}
#endif
}}

@swatanabe
Copy link
Contributor

swatanabe commented Oct 5, 2018 via email

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants