1

我在 C++ 中使用模板类,并且我计划确保与双精度和 mpfr 浮点数的兼容性。程序中发生的唯一除法是除以 2。双精度数和 mpfr 浮点数除以 2 的行为应该不同,因为在 mpfr 中,我可以直接访问指数。

问题:您建议如何生成最有效的编译代码?

  • 我希望检查模板化变量类型的运行时解决方案效率低下。

  • Boost 的 mpfr 包装器似乎没有用,因为它似乎没有使用 mpfr_div_2ui 命令,而是除以值为 2 的 mpfr 浮点数。我希望这比直接更改指数要慢。

  • 我可以使用重载命令来处理 mpfr 浮点数和双精度数的两种情况。

  • 我可以使用一些用户设置的#define 标志,用户需要设置这些标志才能使用 mpfr 数据类型。

  • 还有其他建议吗?

4

1 回答 1

1

我会检查是否number<mpfr_floatXXX>还没有检测到优化。

Boost 的 mpfr 包装器似乎没有用,因为它似乎没有使用 mpfr_div_2ui 命令,而是除以值为 2 的 mpfr 浮点数。我希望这比直接更改指数要慢。

这种期望是没有根据的。只需检查:

#include <boost/multiprecision/mpfr.hpp>

int main() {
    using namespace boost::multiprecision;

    mpfr_float_50 n ("787878787878");
    n /= 2;
}

编译成

mov rax, QWORD PTR fs:40
mov QWORD PTR [rsp+232], rax
xor eax, eax
lea rdi, [rsp+16]
call    mpfr_init2
cmp QWORD PTR [rsp+40], 0
xor ecx, ecx
mov edx, 10
lea rdi, [rsp+16]
call    mpfr_set_str
test    eax, eax
cmp QWORD PTR [rsp+40], 0
lea rsi, [rsp+16]
xor ecx, ecx
mov edx, 2
mov rdi, rsi
call    mpfr_div_ui

所以,它并没有你想象的那么糟糕。

执行

这是我的非通用实现:

mp::mpfr_float_50 div_2ui(mp::mpfr_float_50 const& f, unsigned i) {
    mp::mpfr_float_50 r;
    ::mpfr_div_2ui(
            r.backend().data(), 
            f.backend().data(),
            i,
            MPFR_RNDN);

    return r;
}

通用实现如下所示:

template <typename T, typename Enable = void> struct is_mpfr : boost::mpl::false_ {};

template <unsigned digits10, mp::mpfr_allocation_type AllocationType, mp::expression_template_option ET>
struct is_mpfr<
        mp::number<mp::mpfr_float_backend<digits10, AllocationType>, ET >
    > : boost::mpl::true_ 
{};

template <typename T>
T div_2ui_impl(T f, unsigned i, boost::mpl::false_) {
    while (i--)
        f /= 2;
    return f;
}

template <typename Mpfr>
Mpfr div_2ui_impl(Mpfr f, unsigned i, boost::mpl::true_) {
    std::cout << "-- optimized --";
    Mpfr r;
    ::mpfr_div_2ui(r.backend().data(), f.backend().data(), i, MPFR_RNDN);
    return r;
}

template <typename T>
T div_2ui(T const &f, unsigned i) {
    return div_2ui_impl(f, i, is_mpfr<T> { });
}

现场演示

Live On Coliru

template <typename T>
void test() {
    T n("787878787878");
    n = arith::div_2ui(n, 1);
    std::cout << __FUNCTION__ << ": " << n << "\n";
}

int main() {
    std::cout << std::fixed;

    test<mp::mpfr_float_50>();
    test<mp::mpfr_float_100>();
    test<mp::cpp_int>();
    test<mp::cpp_dec_float_100>();
    test<mp::number<mp::gmp_int> >();
    test<mp::mpf_float_1000>();
}

印刷

-- optimized --test: 393939393939.000000
-- optimized --test: 393939393939.000000
test: 393939393939
test: 393939393939.000000
test: 393939393939
test: 393939393939.000000
于 2015-11-18T17:33:42.687 回答