【发布时间】:2017-11-23 00:31:29
【问题描述】:
这个poly_eval 函数将计算一个多项式的计算结果,该多项式在特定的 x 值处具有一组特定的系数。例如,poly_eval(5, 1, -2, -1) 计算 x^2 - 2x - 1,其中 x = 5。都是 constexpr,所以如果你给它常量,它会在编译时计算答案。
它目前使用递归模板在编译时构建多项式评估表达式,并依赖 C++14 为 constexpr。我想知道是否有人能想到一个删除递归模板的好方法,也许是使用 C++17。练习模板的代码使用来自 clang 和 gcc 的 __uint128_t 类型。
#include <type_traits>
#include <tuple>
template <typename X_t, typename Coeff_1_T>
constexpr auto poly_eval_accum(const X_t &x, const Coeff_1_T &c1)
{
return ::std::pair<X_t, Coeff_1_T>(x, c1);
}
template <typename X_t, typename Coeff_1_T, typename... Coeff_TList>
constexpr auto poly_eval_accum(const X_t &x, const Coeff_1_T &c1, const Coeff_TList &... coeffs)
{
const auto &tmp_result = poly_eval_accum(x, coeffs...);
auto saved = tmp_result.second + tmp_result.first * c1;
return ::std::pair<X_t, decltype(saved)>(tmp_result.first * x, saved);
}
template <typename X_t, typename... Coeff_TList>
constexpr auto poly_eval(const X_t &x, const Coeff_TList &... coeffs)
{
static_assert(sizeof...(coeffs) > 0,
"Must have at least one coefficient.");
return poly_eval_accum(x, coeffs...).second;
}
// This is just a test function to exercise the template.
__uint128_t multiply_lots(__uint128_t num, __uint128_t n2)
{
const __uint128_t cf = 5;
return poly_eval(cf, num, n2, 10);
}
// This is just a test function to exercise the template to make sure
// it computes the result at compile time.
__uint128_t eval_const()
{
return poly_eval(5, 1, -2, 1);
}
另外,我在这里做错了吗?
-------- 对答案的评论--------
下面有两个很好的答案。一个是clear and terse, but may not handle certain situations involving complex types (expression trees, matrices, etc..) well,尽管它做得很好。它还依赖于有点晦涩的 , 运算符。
另一个不太简洁,但仍然是much clearer than my original recursive template, and it handles types just as well。它扩展为 'cn + x * (cn-1 + x * (cn-2 ...'修改为展开到我的递归展开到的内容。
我选择了第一个答案,因为它是第一个,而且它的简洁性更符合我最初问题的精神。但是,如果我要为生产选择一个版本,我会选择第二个。
【问题讨论】:
-
最好包含该函数应该做什么的文字描述。
-
@JohnZwinck - 我添加了一段关于此的内容。
-
如果您假设可以将系数强制转换为廉价复制的通用类型,您可以将参数包粉碎成一个数组并使用循环和索引等熟悉的工具。