4

percent無次元量 (比率など) をパーセンテージで表すことができるように、Boost.Units で単位を実装したいと思います。質量密度単位間の変換を正常に実装しましたが、無次元単位では同じことが機能しません。ここに私のコードがあります(仮定using namespace boost::units;):

//
// gram per milliliter (g mL^-1)
//
namespace my {
        struct gram_per_milliliter_base_unit :
                base_unit<gram_per_milliliter_base_unit, mass_density_dimension, 1>
        {
                static std::string name() {return "gram per milliliter";}
                static std::string symbol() {return "g mL^-1";}
        };
        typedef gram_per_milliliter_base_unit::unit_type gram_per_milliliter_unit;
        BOOST_UNITS_STATIC_CONSTANT(gram_per_milliliter, gram_per_milliliter_unit);
        BOOST_UNITS_STATIC_CONSTANT(grams_per_milliliter, gram_per_milliliter_unit);
}
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
        my::gram_per_milliliter_base_unit, si::mass_density, double, 1.0e3
); // 1 g mL^-1 == 1e3 kg m^-3 (SI unit)
BOOST_UNITS_DEFAULT_CONVERSION(my::gram_per_milliliter_base_unit, si::mass_density);

//
// percentage (%)
//
namespace my {
        struct percent_base_unit :
                base_unit<percent_base_unit, dimensionless_type, 2>
        {
                static std::string name() {return "percent";}
                static std::string symbol() {return "%";}
        };
        typedef percent_base_unit::unit_type percent_unit;
        BOOST_UNITS_STATIC_CONSTANT(percent, percent_unit);
}
BOOST_UNITS_DEFINE_CONVERSION_FACTOR(
        my::percent_base_unit, si::dimensionless, double, 1.0e-2
); // 1 % == 1e-2 (SI dimensionless unit)
BOOST_UNITS_DEFAULT_CONVERSION(my::percent_base_unit, si::dimensionless);

「グラム/ミリリットル」セクションは期待どおりに機能します: このコードをコンパイルできます (同様に仮定using namespace my;します):

quantity<gram_per_milliliter_unit> q1my(3*grams_per_milliliter);
quantity<si::mass_density> q1si(q1my);
quantity<gram_per_milliliter_unit> q1back(q1si);

しかし、以下は両方の変換でコンパイルに失敗します:

quantity<percent_unit> q2my(3*percent);
quantity<si::dimensionless> q2si(q2my);
quantity<percent_unit> q2back(q2si);

G++ 出力: no matching function for call to 'conversion_factor(..., ...)'.

dimensionless_typeこれは、タイプリストの終わりのマーカーのように見えるという事実に関連していますか?

どんな助けや提案も大歓迎です。ありがとうございました。

4

1 に答える 1

5

これは、Dimensionless_type がタイプリストの終わりのマーカーのように見えるという事実に関連していますか?

並べ替え。dimensionless_typeはすべての測定システムに暗黙的に含まれており、それらからすべて同じ方法で抽出されます。 を参照してくださいboost/units/dimensionless_units.hpp

「パーセンテージ」の例では、新しい測定システムがどうなるか、通常のブースト ユニット ルールに従ってどのように指定するかを考えてください。

namespace my {
    ... // define your own unit tag types
    typedef make_system</* your system's units with dimensions*/>::type system;
    ... // unit typedefs, consts, etc.
}

したがって、パーセンテージが無次元になるが、元の無次元とは異なると言う場合、上記の概念に逆らいます。したがって、システム内で 2 つの無次元次元を定義することはできません。

どんな助けや提案も大歓迎です。

ここに 3 つのオプションがあります。

  1. 基礎となる数量タイプをオーバーライドし、割合または通常の数値のいずれかを ctor に受け入れます。http://www.boost.org/doc/libs/release/doc/html/boost_units/Examples.html#boost_units.Examples.UDTExampleを参照してください。

  2. パーセンテージで表示したい場合は、オートスケール機能を試してみてください (自分で行ったことはありませんが、例もあります -- http://www.boost.org/doc/libs/release/doc/html/ boost_units/Examples.html#boost_units.Examples.autoscale )。

  3. 特別なカスタム ディメンション「パーセント」を作成し、明示的にパーセント量との間で変換できます。これはおそらく元の意図に最も近いものですが、ライブラリは「無次元量の次元分析」用に設計されていないため、自動変換が常に行われるとは限りません。システムに自動変換を強制しようとすると、結果がいかに醜いかがわかります。

    //
    // percentage (%)
    //
    namespace my {
        struct percent_base_dimension : 
            base_dimension<percent_base_dimension, 1> {};
        typedef percent_base_dimension::dimension_type percent_type;
    
        struct percent_base_unit :
            base_unit<percent_base_unit, percent_type, 1>
        {
            static std::string name() {return "percent";}
            static std::string symbol() {return "%";}
        };
        typedef make_system<percent_base_unit>::type system;
        typedef percent_base_unit::unit_type percent_unit;
        BOOST_UNITS_STATIC_CONSTANT(percent, percent_unit);
    }
    
    namespace boost { namespace units {
    
    template<class T0, class T1>
    struct conversion_helper<quantity<my::percent_unit, T0>, quantity<si::dimensionless, T1> >
    {
        static quantity<si::dimensionless, T1> convert(const quantity<my::percent_unit, T0>& source)
        {
            return(quantity<si::dimensionless, T1>::from_value(1e-2 * source.value()));
        }
    };
    
    template<class T0, class T1>
    struct conversion_helper<quantity<si::dimensionless, T0>, quantity<my::percent_unit, T1> >
    {
        static quantity<my::percent_unit, T1> convert(const quantity<si::dimensionless, T0>& source)
        {
            return(quantity<my::percent_unit, T1>::from_value(1e+2 * source.value()));
        }
    };
    
    } }
    
    int main()
    {
        using namespace my;
    
        quantity<percent_unit> q2my(3*percent);
    
        //quantity<si::dimensionless> q2si(q2my);
        //The converter won't be picked up due to an explicit disable_if in quantity.hpp:
        // typename boost::disable_if<detail::is_dimensionless_system<System2> >::type* = 0
        //so we manually force the conversion here:
        auto conv = conversion_helper<quantity<percent_unit>, quantity<si::dimensionless> >::convert;
        quantity<si::dimensionless> q2si(conv(q2my));
    
        quantity<percent_unit> q2back(q2si);
    
        std::cout 
            << "q2my: " << q2my << std::endl
            << "q2si: " << q2si << std::endl
            << "q2back: " << q2back << std::endl
            ;
    }
    

    したがって、次のように手動で行うことをお勧めします

    namespace my {
        template<class Y>
        quantity<si::dimensionless, Y> units(const quantity<percent_unit, Y>& source)
        {
            return(quantity<si::dimensionless, Y>::from_value(1e-2 * source.value()));
        }
    
        template<class Y>
        quantity<percent_unit, Y> percentage(const quantity<si::dimensionless, Y>& source)
        {
            return(quantity<percent_unit, Y>::from_value(1e+2 * source.value()));
        }
    
    }
    
    int main()
    {
        using namespace my;
    
        quantity<percent_unit> q2my(3*percent);
        quantity<si::dimensionless> q2si(my::units(q2my));
        quantity<percent_unit> q2back(my::percentage(q2si));
    
        std::cout 
            << "q2my: " << q2my << std::endl
            << "q2si: " << q2si << std::endl
            << "q2back: " << q2back << std::endl
            ;
    }
    

    または、さらに良いことに、型チェックの利点を使用します (したがって、ここでは変換係数を間違えるだけです):

    template<class Y>
    quantity<si::dimensionless, Y> units(const quantity<percent_unit, Y>& source)
    {
        return quantity<si::dimensionless, Y>(1e-2 * source / percent);
    }
    
    template<class Y>
    quantity<percent_unit, Y> percentage(const quantity<si::dimensionless, Y>& source)
    {
        return quantity<percent_unit, Y>(1e+2 * source * percent);
    }
    
于 2013-10-07T15:57:29.953 に答える