Thursday, 16 November 2017

Moving average without overflow


É possível implementar uma média móvel em C sem a necessidade de uma janela de amostras Ive descobri que eu posso otimizar um pouco, escolhendo um tamanho de janela thats um poder de dois para permitir bit-shifting em vez de dividir, mas não necessitando Um buffer seria bom. Existe uma maneira de expressar um novo resultado da média móvel apenas como uma função do antigo resultado e da nova amostra Definir um exemplo de média móvel, através de uma janela de 4 amostras para ser: Adicionar nova amostra e: Uma média móvel pode ser implementada recursivamente , Mas para um cálculo exato da média móvel você deve se lembrar da amostra de entrada mais antiga na soma (ou seja, o a no seu exemplo). Para um comprimento N média móvel você calcula: onde yn é o sinal de saída e xn é o sinal de entrada. Eq. (1) pode ser escrito recursivamente como Então você sempre precisa lembrar a amostra xn-N para calcular (2). Como indicado por Conrad Turner, você pode usar uma janela exponencial (infinitamente longa), que permite calcular a saída somente da saída anterior e da entrada atual: mas esta não é uma média móvel padrão (não ponderada), mas uma média exponencial Ponderada média móvel, onde as amostras mais no passado obter um peso menor, mas (pelo menos em teoria) você nunca esquecer nada (os pesos apenas ficar menor e menor para amostras no passado). Eu implementei uma média móvel sem memória de item individual para um programa de rastreamento GPS que eu escrevi. Eu começo com 1 amostra e dividir por 1 para obter o avg atual. Eu adiciono então uma outra amostra e divido por 2 à corrente avg. Isso continua até que eu chegar ao comprimento da média. Cada vez depois, eu adiciono na nova amostra, obter a média e remover essa média do total. Eu não sou um matemático, mas isso parecia ser uma boa maneira de fazê-lo. Eu imaginei que iria transformar o estômago de um verdadeiro cara de matemática, mas, acontece que é uma das formas aceitas de fazê-lo. E funciona bem. Basta lembrar que quanto maior o seu comprimento mais lento é seguir o que você deseja seguir. Isso pode não importar a maior parte do tempo, mas quando os satélites seguintes, se você é lento, a trilha poderia estar longe da posição real e vai ficar mal. Você poderia ter uma lacuna entre o sat e os pontos de arrasto. Eu escolhi um comprimento de 15 atualizado 6 vezes por minuto para obter suavização adequada e não ficar muito longe da posição real sentado com os pontos de trilha suavizada. Respondida Nov 16 at 23:03 initialize total 0, count0 (cada vez vendo um novo valor Então uma entrada (scanf), um add totalnewValue, um incremento (count), uma divide average (total / count) Esta seria uma média móvel Sobre todas as entradas Para calcular a média apenas sobre as últimas 4 entradas, exigiria 4 variáveis ​​de entrada, talvez copiando cada entrada para uma variável de entrada mais antiga, calculando a nova média móvel como a soma das 4 variáveis ​​de entrada, dividida por 4 Ser bom se todos os insumos foram positivos para fazer o cálculo médio respondido Feb 3 15 at 4:06 Isso vai realmente calcular a média total e não a média móvel. Como a contagem fica maior o impacto de qualquer nova amostra de entrada torna-se desaparecer ndash pequeno Hilmar Eu estou tentando calcular a média de alguns números bastante grandes. Por exemplo: Obviamente, o resultado matemático é 9223372036854775607 (long. MaxValue - 200), mas eu recebo Uma exceção. Isso ocorre porque a implementação (na minha máquina) para o método de extensão Média, conforme inspecionado pelo. NET Reflector é: Eu sei que posso usar uma biblioteca BigInt (sim, eu sei que ela está incluída no. NET Framework 4.0, mas estou vinculado A 3,5). Mas eu ainda me pergunto se theres uma implementação bastante simples de calcular a média de inteiros sem uma biblioteca externa. Por acaso você sabe sobre tal implementação O exemplo anterior, de três inteiros grandes, era apenas um exemplo para ilustrar o problema de estouro. A questão é sobre o cálculo de uma média de qualquer conjunto de números que pode somar um grande número que excede o tipo de valor máximo. Desculpe essa confusão. Eu também mudou o título de perguntas para evitar confusão adicional. Se você sabe aproximadamente o que a média será (ou, pelo menos, que todos os pares de números terão uma diferença máxima lt long. MaxValue), você pode calcular a diferença média desse valor em vez disso. Tomo um exemplo com números baixos, mas funciona igualmente bem com os grandes. É claro que você pode implementar isso de alguma forma que facilita a reutilização, por exemplo como um método de extensão para IEnumerableltlonggt. Respondeu May 24 10 at 8:11 Se you39re unlucky para ter uma lista, ainda vai mal. Mas sua idéia parece legal. Ndash ANeves May 24 10 at 13:53 ANeves - para isso funcionar eu assumi explicitamente que nenhum dois números devem ser mais longos do que long. MaxValue apart. Ndash Tomas Lycken May 24 10 at 15:08 Aqui está como eu faria se dado este problema. Primeiro vamos definir classe RationalNumber muito simples, que contém duas propriedades - Dividendo e Divisor e um operador para adicionar dois números complexos. Aqui está como parece: Segunda parte é realmente fácil. Vamos dizer que temos uma matriz de números. Sua média é estimada por Soma (Números) / Comprimento (Números), que é o mesmo que Número 0 / Comprimento Número 1 / Comprimento. Número n / Comprimento. Para podermos calcular isto representaremos cada Número i / Comprimento como um número inteiro e uma parte racional (lembrete). Aqui está a aparência: no final temos uma lista de números racionais e um número inteiro que somamos juntos e obtemos a média da seqüência sem um estouro. A mesma aproximação pode ser tomada para todo o tipo sem um estouro para ele, e não há nenhuma perda da precisão. Definir: Um conjunto de números. Se Média (A) SUMA (A) / LEN (A) Média (A) A 0 / LEN (A) A 1 / LEN (A) A 2 / LEN (A). AN / LEN (2) se definimos An um número que satisfaz isto: An X (Y / LEN (A)), que é essencialmente porque, se dividir A por B, obtemos X com um lembrete um número racional Y / B). Média (A) A1 A2 A3. AN X1 X2 X3 X4. Lembrete1 Reminder2. Somar as partes inteiras, e somar os lembretes, mantendo-os em forma de número racional. No final temos um número inteiro e um racional, que somados juntos dá Média (A). Dependendo da precisão que você gosta, você aplica isso somente ao número racional no final. Se você sabe de antemão que todos os seus números vão ser grande (no sentido de muito mais próximo long. MaxValue do que zero), você pode calcular a média de sua distância de long. MaxValue. Então a média dos números é long. MaxValue menos isso. No entanto, esta abordagem irá falhar se (m) qualquer um dos números estão longe de long. MaxValue. Assim que seus cavalos para cursos. Respondeu May 24 10 at 8:05 Isto é quase o mesmo que a minha abordagem, mas o seu vai falhar para qualquer número negativo. Ndash Tomas Lycken May 24 10 at 8:15 Eu acho que tem que haver um compromisso em algum lugar ou outro. Se os números estão realmente ficando tão grande, em seguida, poucos dígitos de ordens inferiores (digamos 5 dígitos mais baixos) pode não afetar o resultado tanto. Outra questão é onde você realmente não sabe o tamanho do conjunto de dados chegando, especialmente em casos de fluxo / tempo real. Aqui eu não vejo nenhuma solução diferente da anterior (anteriorAutroContado novoValor) / (oldCount lt - oldCount1) Heres uma sugestão: Averaging números de um tipo numérico específico de uma maneira segura, enquanto também apenas usando esse tipo numérico é realmente possível, embora eu aconselharia Usando a ajuda do BigInteger em uma implementação prática. Eu criei um projeto para cálculos numéricos seguros que tem uma estrutura pequena (Int32WithBoundedRollover) que pode somar até 232 int32s sem nenhum estouro (a estrutura internamente usa dois campos int32 para fazer isso, portanto, não são usados ​​tipos de dados maiores). Uma vez que você tem essa soma, então você precisa calcular soma / total para obter a média, o que você pode fazer (embora eu wouldnt recomendá-lo), criando e, em seguida, incrementando por total outra instância de Int32WithBoundedRollover. Depois de cada incremento, você pode compará-lo com a soma até descobrir a parte inteira da média. De lá você pode descascar fora o restante e calcular a parte fracionária. Existem provavelmente alguns truques inteligentes para tornar isso mais eficiente, mas essa estratégia básica certamente funcionaria sem a necessidade de recorrer a um tipo de dados maior. Dito isto, a implementação atual isnt construir para isso (por exemplo, não há operador de comparação em Int32WithBoundedRollover, embora wouldnt ser muito difícil de adicionar). A razão é que é muito mais simples usar BigInteger no final para fazer o cálculo. Desempenho sábio isso não importa muito para grandes médias, uma vez que só será feito uma vez, e é muito limpa e fácil de entender para se preocupar com algo inteligente (pelo menos até agora.). No que diz respeito à sua pergunta original que estava preocupada com o tipo de dados longo, o Int32WithBoundedRollover poderia ser convertido em um LongWithBoundedRollover por apenas trocar referências int32 para referências longas e ele deve funcionar da mesma maneira. Para Int32s eu notei uma grande diferença no desempenho (no caso que é de interesse). Comparado ao método BigInteger somente, o método que produzi é em torno de 80 mais rápido para as amostras grandes (como no número total de pontos de dados) que eu estava testando (o código para isso está incluído nos testes de unidade para a classe Int32WithBoundedRollover). Isto é provável principalmente devido à diferença entre as operações int32 sendo feito em hardware em vez de software como as operações BigInteger são. Respondeu Mar 30 14 at 3:04 Nice project, I39ll mergulhar nele quando eu puder. Eu estou tentando encontrar uma maneira de calcular uma média cumulativa móvel sem armazenar a contagem e os dados totais que são recebidos até agora. Eu vim para cima com dois algoritmos, mas ambos precisam armazenar a contagem: nova média (dados da antiga contagem de dados antigos) / próxima contagem nova média da média antiga (dados próximos - média antiga) / próxima contagem O problema com esses métodos é que A contagem fica maior e maior, resultando em perda de precisão na média resultante. O primeiro método usa a contagem antiga ea contagem seguinte que são obviamente 1 à parte. Isso me fez pensar que talvez haja uma maneira de remover a contagem, mas infelizmente eu havent encontrado ainda. Ele me fez ficar um pouco mais longe, porém, resultando no segundo método, mas ainda contagem está presente. É possível, ou estou apenas procurando pelo impossível perguntado Sep 28 12 at 8:46

No comments:

Post a Comment