Estou tentando implementar uma rotina de ponto fixo que envolve calcular o valor de para pequenas que se aproxima de . A arquitetura de destino é um FPGA. Um problema é que essa função não se presta facilmente ao uso da expansão de Taylor. Pode-se ver que, para pequenos valores de x, a inclinação de atinge o infinito quando aproxima de , portanto, avaliar a função usando uma série de potências envolve a multiplicação de coeficientes enormes por um pequeno . Este método é, portanto, numericamente instável.
Usando uma abordagem iterativa, o Newton-Raphson produz a seguinte equação iterativa: , onde estamos tentando aproximar . Porém, mais uma vez, como é pequeno, mesma forma teria que ser pequeno para a solução convergir. Como a equação envolve dividir um número pequeno por outro número pequeno, é provável que a aritmética do ponto fixo falhe.
Com isso, gostaria de saber como implementar uma aproximação de valor pequeno para usando aritmética de ponto fixo, usando coeficientes pré-computados ou métodos iterativos.
Respostas:
Uma rotina que eu usei antes (não sei se é "adequada" ou não) é uma abordagem de dividir e conquistar.
Você começa com um valor superior e inferior arbitrário (digamos 5 e 0 respectivamente - as raízes quadradas mais alta e mais baixa que deseja encontrar) e encontra o ponto médio entre elas. Quadrado esse valor.
Se o valor ao quadrado for maior que o seu objetivo, defina o valor superior como seu valor ao quadrado. Se for menor, defina o valor mais baixo.
Repita até que o valor do quadrado corresponda ao seu valor de pesquisa ou você tenha executado iterações suficientes para ter a precisão que desejar.
Aqui está uma pequena versão que reuni em perl:
Obviamente, isso está usando ponto flutuante, mas pode ser facilmente adicionado ao ponto fixo. Você pode variar a precisão alterando o limite de iteração. Cada iteração fica um pouco mais precisa do que a anterior.
por exemplo: - encontre a raiz quadrada de 9:
Se tivesse encontrado o valor 3, teria parado cedo, é claro.
Faça iterações suficientes e deve ser muito preciso:
fonte
Aqui estão algumas idéias e rotinas do mestre / guru transcendente ascendente Scott Dattalo aqui .
É claro que isso é uma piada, exceto a parte do guru (Guru?). Scott é excelente.
Discussão relevante. 2005 e PIC e alguns são C, mas podem ser úteis.
Scott novamente - 2003
Dois Mestres !!!
Dattallo e Golovchenko.
Uma variedade de métodos
fonte
Você não especificou o que quer dizer com "pequeno valor" ou "aproximação". Então, o que estou prestes a propor pode não funcionar, mas aqui vai.
O mais fácil seria criar uma tabela de consulta. Essencialmente, uma ROM em que o barramento de endereços é o número que você deseja com raiz quadrada e a saída de dados é o resultado. Com um único BRAM, você poderia fazer um LUT de 9 bits e 8 bits. Obviamente, mais BRAM's oferecem uma mesa maior.
(BRAM = O termo Xilinx para uma RAM de bloco, que também pode ser usado como ROM. Outros FPGAs têm coisas semelhantes.)
Se você quiser mais precisão do que o BRAM fornecer, poderá fazer uma interpolação linear simples de duas entradas LUT. Por exemplo, digamos que você queira uma entrada de 12 bits, mas você só tem BRAMs para 10 bits. Você pega os 10 bits mais importantes da sua entrada e consulta isso no LUT. Adicione 1 a esses 10 bits e procure também esse valor. Em seguida, você faz uma interpolação linear simples entre os dois resultados, usando os 2 bits inferiores para informar a proporção de um valor sobre o outro. Claro que isso só lhe dará uma aproximação, mas acho que se você fizer as contas, descobrirá que isso pode ser bom o suficiente.
Este método é o menos preciso com números de baixo valor, mas conforme a entrada aumenta para valores mais altos, a precisão aumenta.
Uma otimização do método acima seria usar os BRAMs como uma ROM de porta dupla. Dessa forma, você pode ler dois valores sem aumentar o número de BRAMs usados. Isso também permitirá que você calcule um SQRT para cada ciclo de clock, com alguns atrasos na tubulação.
Aliás, este método também funciona para SINE / COSINE!
fonte
Tente a seguinte abordagem
x <<= 2
em C) até que esteja dentro do intervalo acima.fonte
Tentarx = ( y+ d)2≈y2+ 2 dy
então deixe d= ( x -y2) / 2 anos= ( X / y- y) » 1
e a seguir y= y+ d.
Se MSb for n da direita, deixe primeiroy= 1 ≪ ( n / 2 ) . Converge em <4 iterações.
fonte
Tente: adivinhação aprimorada da 1ª variável
Seu número pode ser considerado: A * 2 ^ n
A primeira aproximação é então: A * 2 ^ (n / 2)
Digamos que você esteja usando um número de 32 bits, com 24 bits usados para armazenar frações. Para números> 1:
1. Conte o número de bits usados na parte inteira (N)
2. Reduza pela metade esse número (N '= N / 2, ou seja,
desloque- se 1 bit para a direita ) 3. Desloque à direita o número original por N' : esse é seu primeiro palpite.
Nesse formato, o menor número que você pode ter é 2 ^ -24. A raiz quadrada terá cerca de 2 ^ -12. Portanto, para números <1:
1. Conte o número de bits "zero" na fração, até atingir um bit definido (N)
2. Divida pela metade esse número (N '= N / 2, ou seja, 1 bit com a direita deslocada)
3. ESQUERDA, desloque o número original pela contagem revisada: este é seu primeiro palpite.
Exemplo:
0,0000 0000 0000 0000 1 [16 zeros à esquerda] se aproxima de: 0,0000 0000 1
Finalmente, se você ainda tiver problemas com o A pequeno: você pode calcular 1 / A?
Nesse caso, inverta seu número e tente usar o algoritmo Raiz quadrada inversa:
x' = 0.5x * (3 - Ax^2)
fonte