如何在Boost :: multiprecision中使用sqrt和ceil? [英] How to use sqrt and ceil with Boost::multiprecision?

查看:170
本文介绍了如何在Boost :: multiprecision中使用sqrt和ceil?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

您知道如何使用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);

然后"ceil"存在错误,可以通过以下方式修复它:

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));

然后出现通用互转换"错误!?!

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

致谢.

解决方案

问题"(实际上是功能)是您正在使用number<>前端且已启用模板表达式./p>

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

您有两个选择:

  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<>从float->整数可能造成的有损转换)来进行工作.

  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>;
    

    在这种特殊情况下,它并没有太大变化,因为您仍然必须从整数->浮点->整数:中键入强制":

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

  3. 通过简化,如果将所有类型改为float(例如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);
    

    注意,请使用您的分析器查看使用et_off不会在代码库上导致性能问题

这是一个演示程序,显示了所有三种方法:

在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);
    }
}

Do you know how to do this simple line of code without error using Boost::multiprecison ?

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

Using MSVC there is an error for "sqrt" and it's possible to fix it with:

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

Then there is an error for "ceil" and it's possible to fix it with:

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));

Then there is an error of "generic interconvertion" !?!

I think there should be a more elegant way to realize a so simple line of code, isn't it? Let me know if you have some ideas about it please.

Regards.

解决方案

The "problem" (it's actually a feature) is that you are using the number<> frontend with template expressions enabled.

This means that many operations can be greatly optimized or even eliminated before code is generated by the compiler.

You have two options:

  1. break things down

    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;
    

    So you could write

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

    Which works by forcing evaluation of expression templates (and potentially lossy conversion from float -> integer using convert_to<>).

  2. In general you could switch to non-expression-template versions of the types:

    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>;
    

    In this particular case it doesn't change much because you still have to do type "coercions" from integer -> float -> integer:

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

  3. By simplifying, if you make all types float instead (e.g. cpp_dec_float) you can get rid of these complicating artefacts:

    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 Use your profiler to see that using et_off doesn't cause a performance problem on your code-base

Here's a demo program showing all three approaches:

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);
    }
}

这篇关于如何在Boost :: multiprecision中使用sqrt和ceil?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆