如何在Boost :: multiprecision中使用sqrt和ceil?

时间:2015-04-05 13:29:28

标签: c++ boost sqrt ceil multiprecision

使用Boost :: multiprecison,您知道如何使用这么简单的代码行而不会出错吗?

boost::multiprecision::cpp_int v, uMax, candidate;
//...
v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);

使用MSVC" sqrt"并且可以通过以下方式解决它:

v += 6 * ceil((sqrt(static_cast<boost::multiprecision::cpp_int>(uMax * uMax - candidate)) - v) / 6);

然后是&#34; ceil&#34;并且可以通过以下方式解决它:

namespace bmp = boost::multiprecision;
typedef bmp::number<bmp::cpp_dec_float<0>> float_bmp;
v += 6 * ceil(static_cast<float_bmp>((sqrt(static_cast<bmp::cpp_int>(uMax * uMax - candidate)) - v) / 6));

然后出现&#34;通用转换错误&#34; !?!

我认为应该有一种更优雅的方式来实现这么简单的代码,不是吗? 如果您对此有任何想法,请告诉我。

问候。

2 个答案:

答案 0 :(得分:4)

&#34;问题&#34; (它实际上是一个功能)是您在启用模板表达式的情况下使用number<>前端。

这意味着在编译器生成代码之前,可以大大优化甚至消除许多操作。

您有两种选择:

  1. 分解

    using BF = boost::multiprecision::cpp_bin_float_100;
    using BI = boost::multiprecision::cpp_int;
    BI v = 1, uMax = 9, candidate = 1;
    
    //v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
    BF tmp1(uMax * uMax - candidate);
    BF tmp2(sqrt(tmp1) - BF(v));
    BF tmp3(ceil(tmp2 / 6));
    BI tmp4(tmp3.convert_to<BI>());
    std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << "\n";
    
    v = v + 6*tmp4;
    

    所以你可以写

    v += 6*ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
    

    通过强制评估表达式模板(以及可能使用convert_to<>从浮点数转换为&gt;整数)来起作用。

  2. 通常,您可以切换到类型的非表达式模板版本:

    using BF = mp::number<mp::cpp_bin_float_100::backend_type, mp::et_off>;
    using BI = mp::number<mp::cpp_int::backend_type, mp::et_off>;
    

    在这种特殊情况下,它并没有太大的变化,因为你仍然需要做类型&#34;强制&#34;来自整数 - &gt;浮动 - &gt;整数:

    v += 6 * ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
    
  3. 通过简化,如果你使所有类型浮动(例如cpp_dec_float),你可以摆脱这些复杂的文物:

    using BF = mp::number<mp::cpp_dec_float_100::backend_type, mp::et_off>;
    BF v = 1, uMax = 9, candidate = 1;
    
    v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
    
      

    CAVEAT 使用您的探查器看到使用et_off不会导致代码库出现性能问题

  4. 这是一个展示所有三种方法的演示程序:

    <强> Live On Coliru

    #include <boost/multiprecision/cpp_int.hpp>
    #include <boost/multiprecision/cpp_bin_float.hpp>
    #include <boost/multiprecision/cpp_dec_float.hpp>
    #include <boost/multiprecision/number.hpp>
    
    int main() {
        namespace mp = boost::multiprecision;
        //v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
        {
            using BF = mp::cpp_bin_float_100;
            using BI = mp::cpp_int;
            BI v = 1, uMax = 9, candidate = 1;
    
    #ifdef DEBUG
            BF tmp1(uMax * uMax - candidate);
            BF tmp2(sqrt(BF(uMax * uMax - candidate)) - BF(v));
            BF tmp3(ceil(tmp2 / 6));
            BI tmp4(tmp3.convert_to<BI>());
            std::cout << tmp1 << " " << tmp2 << " " << tmp3 << " " << tmp4 << "\n";
    #endif
    
            v += 6*ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
        }
    
        {
            using BF = mp::number<mp::cpp_bin_float_100::backend_type, mp::et_off>;
            using BI = mp::number<mp::cpp_int::backend_type, mp::et_off>;
            BI v = 1, uMax = 9, candidate = 1;
    
            v += 6 * ceil((sqrt(BF(uMax * uMax - candidate)) - BF(v)) / 6).convert_to<BI>();
        }
    
        {
            using BF = mp::number<mp::cpp_dec_float_100::backend_type, mp::et_off>;
            BF v = 1, uMax = 9, candidate = 1;
    
            v += 6 * ceil((sqrt(uMax * uMax - candidate) - v) / 6);
        }
    }
    

答案 1 :(得分:0)

使用boost::multiprecision::sqrtboost::multiprecision::ceil