Monday 27 August 2018

Exponencial moving average c ++


Eu perfilei isso usando o Visual C profile, e isso representa cerca de 35 do tempo de execução. Essa média móvel exponencial é chamada mais do que um trilhão de vezes, porque é usada repetidamente no processamento de mais de 400 gigabytes de dados. Os dados estão saindo de uma série de disco de estado sólido Raid Level 0, portanto, lê as contas de dados por menos de 5 do tempo. O tamanho do preço é de cerca de 100. Eu, originalmente, acelerado por um fator de 4, precalculando a maior parte dos dados possível. Então eu consegui aumentá-lo novamente por um fator de ndash PaeneInsula 30 de outubro 11 às 20:41 Eu consegui aumentar a velocidade novamente por um fator de 12 por multithreading (a natureza dos dados é tal que pode ser multithreaded em De tal forma que a carga está perfeitamente equilibrada.) E eu funciono em um i7 990x (que tem 6 núcleos, hipertensos de um total de 12), overclocked. Ndash PaeneInsula 30 de outubro 11 às 20:51 Claro, o multithreading pode ajudar. Mas você quase certamente pode melhorar o desempenho em uma única máquina roscada. Primeiro, você está calculando isso na direção errada. Somente as máquinas mais modernas podem fazer pré-busca de strings negativos. Quase todos os machihnes são mais rápidos para os passos da unidade. Isto é, Mudar a direção da matriz para que você digitalize de baixo a alto, em vez de alto a baixo, é quase sempre melhor. Em seguida, reescrevendo um pouco - permita-me encurtar os nomes das variáveis ​​para facilitar o tipo: Por sinal, vou começar a usar os shorthands p por preço e s para suavizar, para salvar a digitação. Sou preguiçosa. Mas provavelmente é mais rápido. A latência entre avgi e avgi-2 é então 1 multiplicar e adicionar, em vez de subtrair e multiplicar entre avgi e avgi-1. Isto é, Mais de duas vezes mais rápido. Em geral, você deseja reescrever a recorrência para que avgi seja calculado em termos de avgj para j o mais cedo possível, sem preencher a máquina, unidades de execução ou registradores. Você basicamente faz mais multiplicações em geral, para obter menos cadeias de múltiplos (e subtrai) no caminho crítico. Saltar de avgi-2 para avgi é fácil, você provavelmente pode fazer três e quatro. Exatamente em que medida depende do que é a sua máquina e de quantos registros você possui. E a latência do sumador de ponto flutuante e multiplicador. Ou, melhor ainda, o sabor das instruções de multiplicação múltiplas combinadas que você possui - todas as máquinas modernas as possuem. Por exemplo. Se o MADD ou o MSUB tiverem 7 ciclos de duração, você pode fazer até 6 outros cálculos na sua sombra, mesmo se você tiver apenas uma única unidade de ponto flutuante. Totalmente pipelined. E assim por diante. Menos se pipelined em todos os outros ciclos, como é comum para a dupla precisão em chips anteriores e GPUs. O código de montagem deve ser o software pipelined para que diferentes iterações de loop se sobrepõem. Um bom compilador deve fazer isso por você, mas talvez seja necessário reescrever o código C para obter o melhor desempenho. Por sinal: NÃO QUERO sugerir que você esteja criando uma série de valores médios. Em vez disso, você precisaria de duas médias se avgi for calculado em termos de avgi-2, e assim por diante. Você pode usar uma série de avgi se quiser, mas acho que você só precisa ter 2 ou 4 avgs, chamado, criativamente, avg0 e avg1 (2, 3.), e gire-os. Esse tipo de truque, dividindo um acumulador ou média em dois ou mais, combinando múltiplos estágios da recorrência, é comum no código de alto desempenho. Oh, sim: precalcula ss, etc. Se eu fiz isso direito, em infinita precisão, isso seria idêntico. (Verifique-me, por favor.) No entanto, em precisão finita FP, seus resultados podem diferir, espero que apenas um pouco, devido a diferentes arredondamentos. Se o desenrolar estiver correto e as respostas forem significativamente diferentes, você provavelmente terá um algoritmo numericamente instável. Você é quem sabe. Nota: os erros de arredondamento de ponto flutuante mudarão os bits baixos da sua resposta. Ambos por reorganizar o código e usar o MADD. Eu acho que isso provavelmente está bem, mas você tem que decidir. Nota: os cálculos para avgi e avgi-1 agora são independentes. Então, você pode usar um conjunto de instruções SIMD, como Intel SSE2, que permite a operação em dois valores de 64 bits em um registro de 128 bit de largura de cada vez. Isso será bom para quase 2X, em uma máquina que tenha ALUs suficientes. Se você tiver registros suficientes para reescrever avgi em termos de avgi-4 (e tenho certeza que você faz no iA64), então você pode ir 4X de largura, se você tiver acesso a uma máquina como AVX de 256 bits. Em um GPU. Você pode recorrer a recorrências mais profundas, reescrever avgi em termos de avgi-8 e assim por diante. Algumas GPUs têm instruções que calculam AXB ou mesmo AXBY como uma única instrução. Embora isso seja mais comum para 32 bits do que para precisão de 64 bits. Em algum momento, eu provavelmente começaria a perguntar: você quer fazer isso em vários preços por vez. Nem isso ajuda você a multithreading, ele também irá se adequar a isso em uma GPU. E usando o SIMD largo. Adição tardia menor Estou um pouco envergonhada por não ter aplicado a norma Horners para expressões como um pouco mais eficiente. Resultados ligeiramente diferentes com o arredondamento. Na minha defesa, qualquer compilador decente deve fazer isso por você. Mas a regra de Hrners torna a cadeia de dependência mais profunda em termos de multiplica. Você pode precisar desenrolar e pipelined o loop algumas vezes mais. Ou você pode fazer onde você precalcula. Eu sei que isso é viável com o aumento de acordo com: Mas eu realmente gostaria de evitar o uso de impulso. Eu mencionei e não encontrei nenhum exemplo adequado ou legível. Basicamente eu quero acompanhar a média móvel de um fluxo contínuo de um fluxo de números de ponto flutuante usando os números 1000 mais recentes como uma amostra de dados. Qual é a maneira mais fácil de conseguir isso, experimentei usar uma matriz circular, uma média móvel exponencial e uma média móvel mais simples e descobriu que os resultados da matriz circular correspondiam melhor às minhas necessidades. 12 de junho 12 às 4:38 Se suas necessidades são simples, você pode tentar usar uma média móvel exponencial. Simplificando, você faz uma variável de acumulador e, conforme seu código examina cada amostra, o código atualiza o acumulador com o novo valor. Você escolhe um alfa constante que está entre 0 e 1, e calcula isso: Você só precisa encontrar um valor de alfa onde o efeito de uma determinada amostra dura apenas cerca de 1000 amostras. Hmmm, na verdade, não tenho certeza de que isso é adequado para você, agora que eu coloquei aqui. O problema é que 1000 é uma janela bastante longa para uma média móvel exponencial. Não tenho certeza se houver um alfa que espalhe a média nos últimos 1000 números, sem fluxo inferior no cálculo do ponto flutuante. Mas se você quisesse uma média menor, como 30 números ou mais, esta é uma maneira muito fácil e rápida de fazê-lo. Respondeu 12 de junho 12 às 4:44 1 na sua postagem. A média móvel exponencial pode permitir que o alfa seja variável. Então isso permite que ele seja usado para calcular médias base de tempo (por exemplo, bytes por segundo). Se o tempo decorrido desde a última atualização do acumulador for superior a 1 segundo, você deixa alfa ser 1.0. Caso contrário, você pode deixar o alfa ser (usecs desde a última atualização1000000). Ndash jxh 12 de junho 12 às 6:21 Basicamente eu quero acompanhar a média móvel de um fluxo contínuo de um fluxo de números de ponto flutuante usando os 1000 números mais recentes como amostra de dados. Observe que as atualizações abaixo atualizam o total como elementos como adicionados substituídos, evitando a passagem O (N) dispendiosa para calcular a soma - necessária para a demanda média. Total é feito um parâmetro diferente de T para suportar, e. Usando um longo tempo quando totalizando 1000 long s, um int para char s, ou um duplo para float total s. Isso é um pouco falho em que numsamples poderia ultrapassar o INTMAX - se você se importar, você poderia usar um sinal não assinado por muito tempo. Ou use um membro adicional de dados do bool para gravar quando o recipiente é preenchido pela primeira vez ao andar de bicicleta numsamples em torno da matriz (o melhor que renomeou algo inócuo como pos). Respondeu 12 de junho 12 às 5:19 um assume que quotvoid operator (T sample) quot é realmente quotvoid operatorltlt (T sample) quot. Ndash oPless Jun 8 14 às 11:52 oPless ahhh. Bem visto. Na verdade, eu quis dizer que ele seria um operador vazio () (amostra T), mas é claro que você poderia usar qualquer notação que você gostasse. Vou consertar, obrigado. Ndash Tony D 8 jun 14 às 14:27

No comments:

Post a Comment