当前位置:  开发笔记 > 编程语言 > 正文

使用Boost.Units定义百分比

如何解决《使用Boost.Units定义百分比》经验,为你挑选了1个好方法。

我想percent用Boost.Units 实现一个单元,这样无量纲的数量(比如一个比例)可以表示为百分比.我已成功实现了质量密度单位之间的转换,但同样不适用于无量纲单位.这是我的代码(假设using namespace boost::units;):

//
// gram per milliliter (g mL^-1)
//
namespace my {
        struct gram_per_milliliter_base_unit :
                base_unit
        {
                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
        {
                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 q1my(3*grams_per_milliliter);
quantity q1si(q1my);
quantity q1back(q1si);

但是以下两个转换都无法编译:

quantity q2my(3*percent);
quantity q2si(q2my);
quantity q2back(q2si);

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

这是否与dimensionless_type似乎是类型列表结尾的标记有关?

任何帮助或建议将不胜感激.谢谢.



1> Vassilii Kha..:

这是否与dimensionless_type似乎是类型列表结尾的标记有关?

有点.dimensionless_type隐含地包含在每个测量系统中,并以相同的方式从它们中提取,参见boost/units/dimensionless_units.hpp.

在"百分比"示例中,考虑一下您的新测量系统将是什么,以及如何根据通常的增压单位规则指定它:

namespace my {
    ... // define your own unit tag types
    typedef make_system::type system;
    ... // unit typedefs, consts, etc.
}

因此,如果你说你的百分比将是无量纲的,但与原始的无量纲不同,那么你就是在违背上述概念.因此,您无法在系统中定义2个无量纲维度.

任何帮助或建议将不胜感激.

我在这里看到3个选项:

    覆盖基础数量类型并接受ctor中的百分比或常规数字.请参阅http://www.boost.org/doc/libs/release/doc/html/boost_units/Examples.html#boost_units.Examples.UDTExample

    如果你想以百分比显示事物,你可以尝试使用自动缩放功能(从来没有自己完成,但也有一个例子 - http://www.boost.org/doc/libs/release/doc/html/ boost_units/Examples.html#boost_units.Examples.autoscale).

    您可以创建一个特殊的自定义维度"百分比",并显式转换为/来自百分比数量.这可能与您的原始意图最接近,但自动转换并不总是发生,因为库不是为"无量纲数量的维度分析"而设计的.如果您尝试强制系统进行自动转换,您可以看到结果有多丑:

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

    因此,手动执行此操作是个好主意

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

    或者,更好的是,使用类型检查的好处(所以你只能在转换因子中犯一个错误):

    template
    quantity units(const quantity& source)
    {
        return quantity(1e-2 * source / percent);
    }
    
    template
    quantity percentage(const quantity& source)
    {
        return quantity(1e+2 * source * percent);
    }
    

推荐阅读
无名有名我无名_593
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有