2017-08-07 66 views
2
void Clamp(std::vector<double>& input_image, double min_value, double max_value, int width, int height) 
{ 
    for (int j = 0; j < width; j++) 
    { 
     for (int i = 0; i < height; i++) 
     { 
      input_image[i*width + j] = std::min(std::max(input_image[i*width + j], min_value), max_value); 
     } 
    } 
} 

我正在尝试创建钳位功能。std :: vector的C++钳位函数

有没有更好的方法使用std::vector来做到这一点?

我也可以用C++ 11

+2

['std :: transform'](http://en.cppreference.com/w/cpp/algorithm/transform)如何使用简单的lambda?由于您无论如何遍历向量的所有元素,实际上并不需要'width'和'height'参数。 –

+2

如果你可以在C++ 17中做到这一点,尝试对值使用['std :: clamp'](http://en.cppreference.com/w/cpp/algorithm/clamp),而不是拼写它与最小和最大。它更具可读性。如果你不能,那就使用你自己的钳模板。 – StoryTeller

+0

@StoryTeller嘿谢谢我现在不能使用c + + 17。谢谢 – Gilad

回答

2

您可以使用std::transform,假设您将函数应用于每个元素,则不需要高度和宽度参数。拆分最小值和最大值的操作似乎更SIMD友好,所以我建议:

void Clamp(std::vector<double>& input_image, double min_value, double max_value) 
{ 
    std::transform(std::begin(input_image), std::end(input_image), std::begin(input_image), [max_value] (double d) { return std::min(d, max_value); } 
    std::transform(std::begin(input_image), std::end(input_image), std::begin(input_image), [min_value] (double d) { return std::max(d, max_value); } 
} 

否则,C++ 11的方式可能是使用range-based for loop

void Clamp(std::vector<double>& input_image, double min_value, double max_value) // removed hight and width 
{ 
    for (double& d : input_image) 
    { 
     d = std::min(std::max(d, min_value), max_value); 
    } 
} 

或者更多的SIMD“友好” :

void Clamp(std::vector<double>& input_image, double min_value, double max_value) // removed height and width 
{ 
    for (double& d : input_image) 
    { 
     d = std::max(d, min_value); 
    } 
    for (double& d : input_image) 
    { 
     d = std::min(d, max_value); 
    } 
} 
1

你去那里。为了让编译器有更好的优化和向量化机会,我做了两次转换。如果你不同意,你可以加入1 lambda。

std::transform(input_image.begin(), input_image.end(), input_image.begin(), [lo](double v) {return (v < lo ? lo : v);}); 
std::transform(input_image.begin(), input_image.end(), input_image.begin(), [hi](double v) {return (v > hi ? hi : v);}); 

请务必记住,循环访问连续的内存元素要快得多。了解它是如何工作的,请参阅std::transform reference

3

C++ 17 has std::clamp。在这种情况下也不需要参数heightwidth。只要运营商<定义

void clamp_vec(std::vector<double>& input_image, double min_value, double max_value) { 
    std::transform(std::begin(input_image), std::end(input_image), std::begin(input_image), 
        [=] (auto i) { return std::clamp(i, min_value, max_value); }); 
} 

模板版本的泛型类型将工作:

template <typename T> 
void clamp_vec(std::vector<T>& input_image, const T& min_value, const T& max_value) { 
    std::transform(std::begin(input_image), std::end(input_image), std::begin(input_image), 
        [&] (const T& v) { return std::clamp(v, min_value, max_value); }); 
} 

如果std::clamp不可用,你可以实现你自己的,直到C++ 17恶有恶报,例如

template <typename T> 
constexpr const T& clamp(const T& v, const T& lo, const T& hi) { 
    return clamp(v, lo, hi, std::less<>()); 
} 

template <typename T, typename Compare> 
constexpr const T& clamp(const T& v, const T& lo, const T& hi, Compare comp) { 
    return comp(v, lo) ? lo : comp(hi, v) ? hi : v; 
} 
2

我想我只是做一通,让优化器做的工作。

void Clamp(std::vector<double>& input_image, double min_value, double max_value) 
{ 
    auto clamp = [min_value, max_value](double x) { 
     return std::min(std::max(x, min_value), max_value); 
    }; 

    std::transform(input_image.begin(), input_image.end(), 
        input_image.begin(), clamp); 
} 

上godbolt测试此,GCC矢量化,并完全消除的clamp的冗余副本。