c++ - std::reduce 似乎将结果转换为整数

标签 c++ c++17

<分区>

我正在比较这两个函数:

double polynomials(const vector<double> & coeffs, double x) {
    double sum = 0.0;
    double factor = 1.0;
    for (double coeff: coeffs) {
        sum += coeff * factor;
        factor *= x;
    }
    return sum;
}

double algorithm_polynomials(const vector<double> & coeffs, double x) {
    return reduce(execution::seq, cbegin(coeffs), end(coeffs), 0, [factor=1.0, x](double sum, double coeff) mutable {
        double curr_sum = sum + coeff * factor;
        factor *= x;
        return curr_sum;
    });
}

对于整数系数和整数x,这两个函数的结果是等价的。但对于实际值,结果有所不同。第一个函数给出的是正确的,而第二个函数给出的总是整数(不一定接近真实答案)。

我的猜测是每个中间值在求和之前都被转换为整数,但我不明白为什么会发生这种情况,或者我该如何解决它。

要运行此代码,请使用

#include <numeric>
#include <vector>
#include <algorithm>
#include <execution>

using namespace std;

需要带有 -std=c++17 标志的 gcc 9 或更高版本以及从 2019 年到 tbb 的链接。

编辑:感谢大家指出我忽略的初始值类型。

我感到有点惭愧,既因为没有看到它,也因为 reduce 函数使用不当(由于可变的 lambda 而无法将其并行化)。

为了救赎自己,我在这里添加了一种使其并行的方法...

class counter: public std::iterator<
        std::random_access_iterator_tag,   // iterator_category
        size_t,                      // value_type
        size_t,                      // difference_type
        const size_t*,               // pointer
        size_t                       // reference
>{
    size_t num = 0;
public:
    explicit counter(size_t _num) : num(_num) {}
    counter& operator++() {num += 1; return *this;}
    counter operator++(int) {counter retval = *this; ++(*this); return retval;}
    bool operator==(counter other) const {return num == other.num;}
    bool operator!=(counter other) const {return !(*this == other);}
    counter& operator+=(size_t i) { num += i; return *this; }
    counter& operator-=(size_t i) { num -= i; return *this; }
    counter operator +(counter &other) const { return counter(num + other.num);}
    counter operator -(counter &other) const { return counter(num - other.num); }
    counter operator +(size_t i) const { return counter(num + i); }
    counter operator -(size_t i) const {return counter(num - i); }
    reference operator*() const {return num;}
};


double better_algorithm_polinomials(const vector<double> & coeffs, double x) {
    //this has the advantage of being easily parallelized
    return transform_reduce(execution::par, cbegin(coeffs), end(coeffs), counter(0), 0.0, plus{}, [x](double coeff, size_t index) { return coeff * pow<double>(x, index); });
}

最佳答案

std::reduce()的版本您正在调用:

template<class ExecutionPolicy, class ForwardIt, class T, class BinaryOp>
T reduce(ExecutionPolicy&& policy,
         ForwardIt first, ForwardIt last, T init, BinaryOp binary_op);

您可以清楚地看到返回值使用与 init 参数相同的数据类型,在您的例子中它被推导为 int,这就是为什么结果是一个 int

要使返回值成为 double,只需在 init 中将文字 0 更改为 0.0 > 参数:

return reduce(execution::seq, cbegin(coeffs), cend(coeffs), 0.0, ...);

关于c++ - std::reduce 似乎将结果转换为整数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57632895/

相关文章:

c++ - std::reduce 对于 float 有多安全?

c++ - 隐藏 constexpr 计算的最佳方法

生命游戏代码的 C++ 调试

c++ - 在控制结构中定义变量

c++ - Qt 5.5 QOpenGLWidget 链接错误未链接任何 openGL 调用

c# - 在用 C++ 编写的 COM 客户端中抛出空返回值异常

c++ - 操作原始内存的正确数据类型

c++ - 在 std::any 的 std::vector 中找到一个元素

c++ - C++17 引入的求值顺序保证是什么?

c++ - 调用模板时调用重载函数