简体   繁体   English

用于std :: vector的C ++钳位函数

[英]C++ clamp function for a std::vector

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);
        }
    }
}

I am trying to create this functionality of clamping. 我正在尝试创建这种夹紧功能。

Is there a better way to do it using a std::vector ? 有没有更好的方法来使用std::vector

I can also use C++11 我也可以使用C ++ 11

C++17 has std::clamp . C ++ 17有std::clamp Also there's no need for the height and width parameters in this case. 此外,在这种情况下也不需要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 version for generic types will work as long as operator < is defined: 只要定义了operator < ,泛型类型的模板版本就可以工作:

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); });
}

If std::clamp is not available, you can implement your own until C++17 comes around, eg : 如果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;
}

You could use std::transform , assuming that you apply your function to every element then there is no need for the height and width parameters. 您可以使用std :: transform ,假设您将函数应用于每个元素,则不需要height和width参数。 Splitting the min and max operations seems more SIMD friendly, thus I suggest: 分割最小和最大操作似乎更加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); }
}

Otherwise a C++11 way could be to use a range-based for loop : 否则,C ++ 11方式可能是使用基于范围的for循环

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);
    }
}

Or the more SIMD "friendly": 或者更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);
    }
}

I think I'd just do it in one pass and let the optimiser do its work. 我想我只是在一次通过中完成它并让优化器完成它的工作。

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);
}

testing this on godbolt, gcc vectorised it and completely eliminated the redundant copy of clamp . 在godbolt上进行测试,gcc将其矢量化并完全消除了clamp的冗余副本。

There you go. 你去吧 I made two transforms just to give the compiler a better chance for optimizations and vectorization. 我做了两个转换只是为了给编译器提供更好的优化和向量化机会。 You can join them if you wish in 1 lambda if you disagree. 如果您愿意,如果您不同意,可以加入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);});

Always keep in mind that looping over consecutive memory elements is much faster. 始终记住,循环连续的内存元素要快得多。 Refer to std::transform reference to understand how it works. 请参阅std::transform reference以了解它的工作原理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM