模板和划分
Templates and division
我在 C++ 中使用模板化 class,我计划确保与双精度和 mpfr 浮点数的兼容性。程序中发生的唯一除法是除以 2。除以 2 的双精度和 mpfr 浮点数的行为应该不同,因为在 mpfr 中,我可以直接访问指数。
问题:您有什么建议可以产生最高效的编译代码?
我预计检查模板变量类型的 运行 时间解决方案效率低下。
Boost 的 mpfr 包装器似乎没有用,因为它似乎没有使用 mpfr_div_2ui 命令,而是除以值为 2 的 mpfr 浮点数。我希望这比直接改变指数要慢。
我可以使用重载命令来处理 mpfr 浮点数和双精度数的两种情况。
我可以使用一些用户设置的#define 标志,用户需要设置这些标志才能使用 mpfr 数据类型。
还有其他建议吗?
我会检查 number<mpfr_floatXXX>
是否尚未检测到优化。
Boost's mpfr wrapper does not seem useful because it doesn't seem to use the mpfr_div_2ui command and would, instead, divide by the mpfr float with a value of 2. I expect this to be slower than directly changing the exponent.
这种期望是没有根据的。只需检查:
#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> { });
}
现场演示
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
我在 C++ 中使用模板化 class,我计划确保与双精度和 mpfr 浮点数的兼容性。程序中发生的唯一除法是除以 2。除以 2 的双精度和 mpfr 浮点数的行为应该不同,因为在 mpfr 中,我可以直接访问指数。
问题:您有什么建议可以产生最高效的编译代码?
我预计检查模板变量类型的 运行 时间解决方案效率低下。
Boost 的 mpfr 包装器似乎没有用,因为它似乎没有使用 mpfr_div_2ui 命令,而是除以值为 2 的 mpfr 浮点数。我希望这比直接改变指数要慢。
我可以使用重载命令来处理 mpfr 浮点数和双精度数的两种情况。
我可以使用一些用户设置的#define 标志,用户需要设置这些标志才能使用 mpfr 数据类型。
还有其他建议吗?
我会检查 number<mpfr_floatXXX>
是否尚未检测到优化。
Boost's mpfr wrapper does not seem useful because it doesn't seem to use the mpfr_div_2ui command and would, instead, divide by the mpfr float with a value of 2. I expect this to be slower than directly changing the exponent.
这种期望是没有根据的。只需检查:
#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> { });
}
现场演示
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