Eu tenho recursos muito limitados, pois estou trabalhando com um microcontrolador. Existe uma expansão da série Taylor, uma tabela de pesquisa comum ou uma abordagem recursiva?
Eu preferiria fazer algo sem usar o sqrt () do math.h
algorithms
c
numerical-algorithms
tarabyte
fonte
fonte
Respostas:
se você quer uma expansão de séries de potência otimizada barata e suja (os coeficientes da série de Taylor convergem lentamente) para
sqrt()
um monte de outros trancendentais, eu tenho algum código de muito tempo atrás. Eu costumava vender esse código, mas ninguém me pagou por quase uma década. então eu acho que vou lançá-lo para consumo público. esse arquivo específico era para um aplicativo em que o processador tinha ponto flutuante (precisão única IEEE-754) e eles tinham um compilador C e um sistema dev, mas não tinhampossui (ou não queria vincular) o stdlib que teria as funções matemáticas padrão. eles não precisavam de precisão perfeita, mas queriam que as coisas fossem rápidas. você pode facilmente fazer engenharia reversa do código para ver quais são os coeficientes da série de potência e escrever seu próprio código. esse código assume o IEEE-754 e mascara os bits para mantissa e expoente.parece que a "marcação de código" que o SE possui não é amigável com caracteres angulares (você sabe ">" ou "<"); portanto, você provavelmente precisará clicar em "editar" para ver tudo.
fonte
stdlib
.Se você ainda não viu, a "raiz quadrada do Quake" é simplesmente confusa. Ele usa alguma mágica no nível de bit para fornecer uma boa primeira aproximação e, em seguida, usa uma ou duas rodadas da aproximação de Newton para revisar. Pode ser útil se você estiver trabalhando com recursos limitados.
https://en.wikipedia.org/wiki/Fast_inverse_square_root
http://betterexplained.com/articles/understanding-quakes-fast-inverse-square-root/
fonte
Você também pode aproximar a função de raiz quadrada usando o Método de Newton . O método de Newton é uma maneira de aproximar onde estão as raízes de uma função. É também um método iterativo em que o resultado da iteração anterior é usado na próxima iteração até a convergência. A equação do método de Newton para adivinhar onde a raiz tem uma função dada uma suposição inicial é definida como:f(x) x0
Para usar o método de Newton para aproximar a raiz quadrada, suponha que recebamos um número . Como tal, para calcular a raiz quadrada, precisamos calcular Dessa forma, procuramos encontrar uma resposta tal que . Esquadre os dois lados e movendo para o outro lado da equação produz . Como tal, a resposta para esta equação é e, portanto, é a raiz da função. Como tal, seja a equação da qual queremos encontrar a raiz. Substituindo isso no método de Newton, e, portanto:a a−−√ x=a−−√ a x2−a=0 a−−√ f(x)=x2−a f′(x)=2x
Portanto, para calcular a raiz quadrada de , precisamos simplesmente calcular o método de Newton até convergir. No entanto, como observado por @ robertbristow-johnson, a divisão é uma operação muito cara - especialmente para microcontroladores / DSPs com recursos limitados. Além disso, pode haver um caso em que um palpite pode ser 0, o que resultaria em um erro de divisão por 0 devido à operação de divisão. Como tal, o que podemos fazer é usar o método de Newton e resolver a função recíproca , por exemplo, . Isso também evita qualquer divisão, como veremos mais adiante. Esquadrar os dois lados e mover para o lado esquerdo resulta em . Portanto, a solução para isso seriaa 1x=a−−√ a−−√ 1x2−a=0 1a√ . Ao multiplicar por , obteríamos o resultado pretendido. Novamente, usando o método de Newton, temos assim:a
No entanto, há um aviso que devemos considerar ao examinar a equação acima. Para raízes quadradas, a solução deve ser positiva e, para que as iterações (e o resultado) sejam positivas, a seguinte condição deve ser atendida:
3 x n > ( x n ) 3 a ( x n ) 2 a < 3
Portanto:
Portanto, dado o número do qual desejamos calcular a raiz quadrada, a suposição inicial deve satisfazer a condição acima. Como isso finalmente será colocado em um microcontrolador, poderíamos começar com qualquer valor de (por exemplo, 1), e continuar repetindo e diminuindo o valor de até que a condição acima seja satisfeita. Observe que evitei fazer divisão para calcular diretamente qual o valor dex 0 x 0 10 - 6x0 x0 x0 deve ser como divisão é uma operação cara. Quando tivermos o nosso palpite inicial, repita o método de Newton. Observe que, dependendo da estimativa inicial, pode levar um tempo menor ou maior para convergir. Tudo depende de quão perto você está da resposta real. Você pode limitar o número de iterações ou aguardar até que a diferença relativa entre as duas raízes seja menor que algum limite (como ou mais).10−6
Como sua tag está procurando um algoritmo
C
, vamos escrever um muito rapidamente:Esta é uma implementação bastante básica do método de Newton. Observe que eu continuo diminuindo a estimativa inicial pela metade até que a condição da qual falamos anteriormente seja satisfeita. Também estou tentando encontrar a raiz quadrada de 5. Sabemos que isso é aproximadamente igual a 2.236 ou mais. O uso do código acima fornece a seguinte saída:
Observe que o método de Newton é encontrar a solução da solução recíproca e multiplicamos por no final para obter nossa resposta final. Além disso, observe que o palpite inicial foi alterado para garantir que os critérios mencionados acima sejam atendidos. Apenas por diversão, vamos tentar encontrar a raiz quadrada de 9876.a
Como você pode ver, a única coisa diferente é quantas iterações são necessárias para calcular a raiz quadrada. Quanto maior o número do que você deseja calcular, mais iterações serão necessárias.
Eu sei que esse método já foi sugerido em uma postagem anterior, mas achei que derivaria o método e forneceria algum código!
fonte
Sim, uma série de potências pode aproximar rápida e eficientemente a função de raiz quadrada e apenas em um domínio limitado. quanto maior o domínio, mais termos serão necessários em sua série de potências para manter o erro suficientemente baixo.
Onde
portanto, se sua implementação for um ponto fixo, você precisará alterar seus bits (contando o número de posições de bits alteradas) até que seus valores estejam entre 1 e 2 usando a escala do seu esquema de ponto fixo. se você deslocar para a direita [esquerda] o argumento em bits para obter o argumento entre 1 e 2, o resultado deverá ser deslocado para a esquerda [direita] em bits. se o número de bits de deslocamento for ímpar, o deslocamento extra de bits será compensado com uma multiplicação adicional de , que pode ser armazenada como uma constante no seu código.n √2n n 2–√
se for ponto flutuante, você precisará separar o expoente e a mantissa como meu código C faz na outra resposta.
fonte
Na verdade, isso é feito resolvendo uma equação quadrática usando o Método Newton:
http://en.wikipedia.org/wiki/Methods_of_computing_square_roots
Para números maiores que um, você pode usar a seguinte expansão de Taylor:
http://planetmath.org/taylorexpansionofsqrt1x
fonte
Dentro de 4% de precisão, se bem me lembro. Foi usado por engenheiros, antes de réguas e calculadoras logarítmicas. Eu aprendi isso em Notes et formules de l'ingénieur, De Laharpe , 1923
fonte