Eu sei que os valarrays têm um pouco de açúcar sintático
Eu tenho que dizer que acho que não std::valarrays
tem muito açúcar sintático. A sintaxe é diferente, mas eu não chamaria a diferença de "açúcar". A API é estranha. A seção std::valarray
s na linguagem de programação C ++ menciona essa API incomum e o fato de que, desdestd::valarray
se espera que seja altamente otimizado, todas as mensagens de erro que você recebe ao usá-las provavelmente não serão intuitivas.
Por curiosidade, cerca de um ano atrás eu opus std::valarray
contra std::vector
. Não tenho mais o código ou os resultados precisos (embora não deva ser difícil escrever o seu próprio). Usando GCC I fez ficar um pouco benefício de desempenho quando se utiliza std::valarray
para a matemática simples, mas não para os meus implementações para calcular o desvio padrão (e, claro, o desvio padrão não é tão complexo, na medida em matemática vai). Eu suspeito que as operações em cada item em uma grande std::vector
peça melhor com caches do que as operações em std::valarray
s. ( NOTA , seguindo os conselhos de musiphil , eu consegui um desempenho quase idêntico de vector
e valarray
).
No final, decidi usar std::vector
prestando muita atenção a coisas como alocação de memória e criação temporária de objetos.
Ambos std::vector
e std::valarray
armazenam os dados em um bloco contíguo. No entanto, eles acessam esses dados usando padrões diferentes e, mais importante, a API std::valarray
incentiva diferentes padrões de acesso que a API std::vector
.
Para o exemplo de desvio padrão, em uma etapa específica, eu precisava encontrar a média da coleção e a diferença entre o valor de cada elemento e a média.
Para o std::valarray
, eu fiz algo como:
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> temp(mean, original_values.size());
std::valarray<double> differences_from_mean = original_values - temp;
Eu posso ter sido mais inteligente com std::slice
ou std::gslice
. Já faz mais de cinco anos.
Pois std::vector
, eu fiz algo como:
std::vector<double> original_values = ... // obviously, I put something here
double mean = std::accumulate(original_values.begin(), original_values.end(), 0.0) / original_values.size();
std::vector<double> differences_from_mean;
differences_from_mean.reserve(original_values.size());
std::transform(original_values.begin(), original_values.end(), std::back_inserter(differences_from_mean), std::bind1st(std::minus<double>(), mean));
Hoje certamente escreveria isso de maneira diferente. Se nada mais, eu aproveitaria o C ++ 11 lambdas.
É óbvio que esses dois trechos de código fazem coisas diferentes. Por um lado, o std::vector
exemplo não cria uma coleção intermediária como o std::valarray
exemplo. No entanto, acho justo compará-los porque as diferenças estão ligadas às diferenças entre std::vector
e std::valarray
.
Quando escrevi esta resposta, suspeitei que subtrair o valor dos elementos de dois std::valarray
s (última linha no std::valarray
exemplo) seria menos compatível com o cache do que a linha correspondente no std::vector
exemplo (que também é a última linha).
Acontece, no entanto, que
std::valarray<double> original_values = ... // obviously I put something here
double mean = original_values.sum() / original_values.size();
std::valarray<double> differences_from_mean = original_values - mean;
Faz a mesma coisa que o std::vector
exemplo e tem desempenho quase idêntico. No final, a questão é qual API você prefere.