Pergunta

I would like to use the algorithms of std::numeric to compute the sum of the absolute values of an array, in order to use the gnu parallel extensions (array size is > 500000).

Here is my current code :

double ret = 0;
for (auto i = 0U; i < length; ++i)
{
    ret += std::abs(tab[i]);
}
return ret;

So I thought about doing :

auto sumabs = [] (double a, double b) 
{
    return std::abs(a) + std::abs(b);
} 

std::accumulate(tab, tab + length, 0, sumabs);

But it is inefficient because if a reduction algorithm is performed (which I sincerely hope for the sake of fast computation!), std::abs will be applied to values which are already >= 0.

So is there any way to do this ? perhaps performing the first step of the reduction "by hand", and let std::accumulate do a simple addition between the rest ? But there will be a copy and a memory hit...

Foi útil?

Solução

You can pass a function to the accumlate method and perform the "by hand" evaluation inside the function. By the way in your code you apply the abs method to the first parameter which is not necessary.

int fAccumulate (int accumulated, int accumulateIncrement) 
{
    int retValue = 0;
    if (accumulateIncrement >= 0)
    {
        retValue = accumulated + accumulateIncrement;
    }
    else
    {
        retValue = accumulated + std::abs(accumulateIncrement);
    }
    return retValue;
}

The use of this code could be:

int init = 0;
int numbers[] = {10,20,-30};
int a = std::accumulate (numbers, numbers+3, init, fAccumulate);

Outras dicas

This will use the minimum number of calls to std::abs necessary:

#include <algorithm>
#include <cmath>

int main() {
    static const auto abssum = [] (auto x, auto y) {return x + std::abs(y);};
    
    float entries[4] = {1.0f, 2.0f, 3.0f, 4.0f};

    auto sum = std::accumulate(std::begin(entries), std::end(entries), 0.0f, abssum);
}
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top