Comment effectuer une approximation de petite valeur pour sqrt (x) sur FPGA


8

J'essaie de mettre en œuvre une routine à virgule fixe qui implique le calcul de la valeur de X pour les petits X qui approche 0. L'architecture cible est un FPGA. Un problème est que cette fonction ne se prête pas facilement à l'utilisation de l'expansion de Taylor. On peut voir que pour les petites valeurs de x, la pente deX va à l'infini quand X approches 0, l'évaluation de la fonction à l'aide d'une série de puissances implique donc de multiplier d'énormes coefficients par un petit X. Cette méthode est donc numériquement instable.

En utilisant une approche itérative, le Newton-Raphson donne l'équation itérative suivante: Xn+1=Xn2-α2Xn, où nous essayons d'approximer α. Mais encore une fois, puisqueα est petite, Xndevrait également être petit pour que la solution converge. Puisque l'équation implique de diviser un petit nombre par un autre petit nombre, il est probable que l'arithmétique à virgule fixe échoue.

Sur ce, je voudrais savoir comment implémenter une approximation de petite valeur pour X en utilisant l'arithmétique à virgule fixe, soit en utilisant des coefficients précalculés ou des méthodes itératives.


2
Si vous ciblez un FPGA, la première et la plus importante question est de savoir quelle précision vous souhaitez. Vous dites que vous voulez utiliser le point fixe: quelle précision pour l'entrée, quelle précision pour le résultat? En virgule fixe (comme dans les entiers) il n'y a pas de "zéro proche". Il n'y a qu'un plus petit nombre qui vous intéresse.
Philippe

Réponses:


5

Une routine que j'ai utilisée auparavant (je ne sais pas si c'est une "bonne" ou non) est une approche diviser pour mieux régner.

Vous commencez avec une valeur arbitraire supérieure et inférieure (disons 5 et 0 respectivement - les racines carrées les plus hautes et les plus basses que vous voulez trouver) et trouvez le milieu entre elles. Mettez cette valeur au carré.

Si la valeur au carré est supérieure à votre cible, définissez la valeur supérieure comme votre valeur au carré. S'il est inférieur, définissez la valeur inférieure.

Répétez jusqu'à ce que la valeur carrée corresponde à votre valeur de recherche ou que vous ayez exécuté suffisamment d'itérations pour être aussi précis que vous le souhaitez.

Voici une petite version que j'ai réunie en perl:

#!/usr/bin/perl

my $val = shift;

my $max = 5;
my $min = 0;

my $iterations = 0;
my $maxiter = 40;

while(($max > $min) and ($iterations<$maxiter))
{
    $iterations++;
    my $diff = $min + ($max - $min) / 2;
    my $square = $diff * $diff;

    if($square == $val)
    {

        print "Square root found at $diff\n";
        print "$iterations iterations\n";
        exit(0);
    } else {
        if($square > $val)
        {
            $max = $diff;
        } else {
            $min = $diff;
        }
    }
}

my $diff = $min + ($max - $min) / 2;
print "Approximate square root after $iterations iterations: $diff\n";

Bien sûr, cela utilise la virgule flottante, mais pourrait facilement être adapté au point fixe. Vous pouvez modifier la précision en modifiant la limite d'itération. Chaque itération est légèrement plus précise que la précédente.

ex: - trouver la racine carrée de 9:

Approximate square root after 40 iterations: 2.99999999999955
   - or - 
Approximate square root after 10 iterations: 3.00048828125
   - or - 
Approximate square root after 5 iterations: 3.046875

S'il avait trouvé la valeur 3, il se serait arrêté très tôt.

Donnez-lui suffisamment d'itérations et il devrait être très précis:

./sqrt.pl 0.00284
Square root found at 0.0532916503778969
59 iterations

2
Fondamentalement, une recherche binaire.
rfusca

Connaissez-vous une méthode pour choisir la valeur de départ?
Ang Zhi Ping

C'est la racine carrée du plus grand nombre auquel vous vous attendez.
Majenko


3

Vous n'avez pas spécifié ce que vous entendez par "petite valeur" ou "approximation". Donc ce que je suis sur le point de proposer pourrait ne pas fonctionner, mais voilà.

Le plus simple serait de faire une table de correspondance. Essentiellement une ROM où le bus d'adresse est le nombre que vous souhaitez enraciné au carré et la sortie de données est le résultat. Avec un seul BRAM, vous pourriez faire une LUT de 9 bits, 8 bits de sortie. Bien sûr, plus de BRAM vous donneront une table plus grande.

(BRAM = Le terme Xilinx pour une RAM de bloc, qui peut également être utilisé comme ROM. D'autres FPGA ont des choses similaires.)

Si vous voulez plus de précision que BRAM ne vous en donnera, vous pouvez faire une simple interpolation linéaire de deux entrées LUT. Par exemple, disons que vous voulez une entrée 12 bits, mais vous n'avez que des BRAM pour 10 bits. Vous prenez les 10 premiers bits de votre entrée et recherchez cela dans la LUT. Ajoutez 1 à ces 10 bits et recherchez également cette valeur. Vous effectuez ensuite une simple interpolation linéaire entre les deux résultats, en utilisant les 2 derniers bits pour vous indiquer la proportion d'une valeur par rapport à l'autre. Bien sûr, cela ne vous donnera qu'une approximation, mais je pense que si vous faites le calcul, vous constaterez que cela pourrait être assez bon.

Cette méthode est la moins précise avec des nombres de faible valeur, mais lorsque l'entrée va à des valeurs plus élevées, la précision augmente considérablement.

Une optimisation de la méthode ci-dessus serait d'utiliser les BRAM en tant que ROM à double port. De cette façon, vous pouvez lire deux valeurs sans augmenter le nombre de BRAM utilisés. Cela vous permettra également de calculer un SQRT pour chaque cycle d'horloge, avec quelques retards de pipeline.

Soit dit en passant, cette méthode fonctionne également pour SINE / COSINE!


Une petite valeur signifie que x approche de 0, c'est pourquoi je m'intéresse à l'approximation de petite valeur de \ sqrt {x}.
Ang Zhi Ping

1
@angzhiping "Approaching zero" n'aide pas. Nous devons connaître la portée et la précision. Ce que vous avez donné est la moitié de la plage et aucune précision. Le résultat final est de connaître le nombre de bits d'entrée et de sortie. La vitesse requise est également importante: en termes de vitesse d'horloge et d'horloges par sqrt.

3

Essayez l'approche suivante

  • Si le nombre est négatif, gérez-le en conséquence.
  • Si le nombre est 0, retournez 0.
  • Autrement:
  • normaliser à un nombre dans la plage [1/4, 1]: comptez combien de fois k vous devez multiplier votre nombre par 4 ( x <<= 2en C) jusqu'à ce qu'il soit dans la plage ci-dessus.
  • utiliser une approche arbitraire (approximations polynomiales, méthode de Newton pour sqrt a [n] = (a [n-1] + k / a [n-1]) / 2, etc.) pour calculer la racine carrée dans cette plage
  • dénormaliser: décaler vers la droite de k bits

0

Essayer X=(y+)2y2+2y alors laisse =(X-y2)/2y=(X/y-y)1 et ensuite y=y+. Si MSb est n de droite, laissez d'abordy=1(n/2). Converge en <4 itérations.


0

Essayez: deviner mieux pour la 1ère variable

Votre numéro peut être considéré: A * 2 ^ n
La 1ère approximation est alors: A * 2 ^ (n / 2)

Supposons que vous utilisez un nombre de 32 bits, avec 24 bits utilisés pour contenir des fractions. Pour les nombres> 1:
1. Comptez le nombre de bits utilisés dans la partie entière (N)
2. Réduisez de moitié ce nombre (N '= N / 2, c'est-à-dire 1 bit décalé vers la droite)
3. Décalez vers la droite le nombre original de N' : c'est votre première supposition.

Dans ce format, le plus petit nombre que vous pouvez avoir est 2 ^ -24. La racine carrée sera d'environ 2 ^ -12. Donc, pour les nombres <1:
1. Comptez le nombre de bits "zéro" dans la fraction, jusqu'à ce que vous atteigniez un bit défini (N)
2. Réduisez de moitié ce nombre (N '= N / 2, c'est-à-dire 1 bit décalé vers la droite)
3. GAUCHE décaler le nombre d'origine par le nombre révisé: c'est votre première supposition.

Exemple:
0,0000 0000 0000 0000 1 [16 zéros de tête] correspond approximativement à: 0,0000 0000 1

Enfin, si vous avez toujours des problèmes avec le petit A: pouvez-vous calculer 1 / A?
Si c'est le cas, inversez votre numéro, puis essayez d'utiliser l'algorithme Inverse Square Root:
x' = 0.5x * (3 - Ax^2)

En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.