2017-07-11 4 views
0

Je suis en train de courir un algorithme qui prend du temps avec le programme bare-metal (sans OS) sur notre carte en utilisant un processeur (architecture sparc) développé en notre équipe, et en utilisant gcc elf toolchain. Avec soft-float, ça marche bien, et j'obtiens le résultat désiré après plus d'une heure (c'est purement logiciel, ça sera beaucoup plus court avec du matériel spécial plus tard). Mais en utilisant hard-float, je peux le faire en 15 minutes, bon résultat. OK, mais dans une certaine configuration de cas hard-float, je vois que la fonction exp() ne fonctionne pas correctement. Ce cas est où je veux imprimer float correctement.Dans elf-gcc, exp() fonctionne correctement seulement pour le premier appel que pas après

J'ai écrit un code de test pour tester la fonction exp(),

ab_printf("------- exp test--------\n"); 
float a[5] = {-0.438984, -0.357934, 0.174203, 0.280720, 0.372380}; 
for(i=0;i<5;i++){ 
ab_printf("x = %f, y = %f\n", a[i], 1./(1.+exp(-1.*a[i]))); 
} 
ab_printf("------- end of exp test--------\n"); 

Lorsque j'utilise Softfloat (avec -msoft flottant dans le Makefile), j'obtenir le bon résultat.

------- exp test-------- 
x = -0.438984, y = 0.391983 
x = -0.357934, y = 0.411460 
x = 0.174203, y = 0.543441 
x = 0.280720, y = 0.569723 
x = 0.372380, y = 0.592034 
------- end of exp test-------- 

Ensuite, je passe à flotteur dur (en utilisant du matériel FPU, = supprimer -msoft-flotteur pour générer des instructions de flotteur de matériel), mais je comprends la fonction exp() est mis en œuvre par l'ensemble d'outils en utilisant le logiciel. (il n'y a pas d'instruction exp dans la CPU, donc la bibliothèque de la chaîne d'outils utilisera l'extension Taylor ou quelque chose comme ça ..). J'utilise deux bibliothèques comme ci-dessous pour linker lors de l'utilisation de hard-float.

LIBS  += -L/opt/abde/lib/gcc/sparc-ab-elf/4.6.2/soft/v8 # line 1 
LIBS  += -L/opt/abde/sparc-ab-elf/lib/soft/v8 # line 2 

Si je v8 au lieu de doux/v8 dans la ligne 1, arrête le programme lors de l'impression numéro de flotteur de sorte que n'est pas une option. Je soupçonne que mon ensemble d'outils n'a pas été construit correctement, mais je ne peux pas le construire dans mon système pour le moment.

Si j'utilise v8 au lieu de soft/v8 dans la ligne 2, je vois des données brouillées pour le nombre flottant. Mais je sais que je peux obtenir un bon résultat de détection dans cette configuration, même si je vois quelques petites erreurs flottantes se développer au fur et à mesure du traitement, et je sais que dans cette configuration, exp() fonctionne aussi (15 minutes) .

En mode disque flottant, quand je lance de i = 0, il me donne ce résultat (seul le premier a travaillé correct):

------- exp test-------- 
x = -0.438984, y = 0.391983 
x = -0.357934, y = 1.000000 
x = 0.174203, y = 1.000000 
x = 0.280720, y = 1.000000 
x = 0.372380, y = 1.000000 
------- end of exp test-------- 

quand je le lance de I = 1, il me donne (aussi, seulement le premier correct)

------- exp test-------- 
x = -0.357934, y = 0.411460 
x = 0.174203, y = 1.000000 
x = 0.280720, y = 1.000000 
x = 0.372380, y = 1.000000 
------- end of exp test-------- 

Quel cas cela serait-il? Le problème est que je ne peux pas construire la chaîne d'outils en ce moment sur mon système.

+0

Une possibilité est que quelque chose dans le traitement ab_printf gâche le flottant matériel. Pour tester cette théorie, vous pouvez stocker les résultats dans un tableau de la boucle et les sortir uniquement d'une boucle ultérieure. –

+0

c'est une bonne idée, j'ai essayé mais ce n'était pas le cas. Merci! –

+1

Vous obtenez des résultats erronés pour d'autres fonctions 'math.h', comme' sin', 'atan', etc., ou le problème est-il spécifique à' exp'? Il serait bon d'éliminer également les problèmes 'printf', étant donné que le code convertissant un flottant en nombre décimal pour la sortie peut être nettement plus compliqué que le code exécutant' exp'. –

Répondre

0

Faire que le programme fonctionne avec les flottants et non les valeurs doubles. Si vous utilisez littéral comme 1.0, il est double. Utilisez plutôt 1.0f. exp prend un double paramètre et renvoie double. 1. + exp (-1. * A [i]) convertira un [i] en double, puis effectuera les doubles opérations, puis convertira à nouveau en un seul float. Cela a un impact assez important sur la précision. Je ne sais pas quels numéros (32 ou 64 bits) votre FPU utilise. Faites-les tous pareils à ceux du FPU.

note que vous avez différentes fonctions exp en fonction du type de flotteur (expf, exp, expl)

+0

J'ai vérifié que ce n'est pas lié à float, double. Si je l'imprime sans boucle, en utilisant l'index explicite de 0,1,2,3, .. il les imprime ok. Il semble que la fonction ab_printf ait un problème lors de l'impression avec float..in la boucle. –

+0

comment l'avez-vous vérifié? Les as-tu fait flotter? –

+0

Si j'imprime comme ab_printf ("x =% f, y =% f \ n", a [0], sin (a [0])); ab_printf ("x =% f, y =% f \ n", a [1], sin (a [1])); ab_printf ("x =% f, y =% f \ n", a [2], sin (a [2])); ab_printf ("x =% f, y =% f \ n", a [3], sin (a [3])); ab_printf ("x =% f, y =% f \ n", a [4], sin (a [4])); il imprime ok, mais si j'utilise pour (i = 0; i <5; i ++) ab_printf ("x =% f, y =% f \ n", un [i], sin (a [i])) ; il ne l'imprime pas correctement, les valeurs sont fausses. Donc, ce n'est pas un problème flottant/double. –

-1

On dirait qu'il a un problème avec l'impression de flotter usinb ab_printf. J'ai trouvé une autre plate-forme a un autre problème d'impression flottant. (https://github.com/esp8266/Arduino/issues/341). J'ai donc choisi d'utiliser cette configuration:

LIBS  += -L/opt/abde/lib/gcc/sparc-ab-elf/4.6.2/soft/v8 # line 1 
LIBS  += -L/opt/abde/sparc-ab-elf/lib/v8 # line 2 

Cette configuration me permet d'utiliser des disques flottant sans problème autre que printf flottant. SO pour imprimer la valeur float j'ai décidé de faire disparaître faire comme (int) (1 ./ (1.+ exp (-1. * a [i])) * 10000.) et utilise un nombre entier décimal. J'espère que quelqu'un pourrait venir avec une autre bonne solution.

+0

Détail: 'ab_printf (" y =% f \ n ", 1 ./ (1. + exp (-1. * A [i])));' -> c'est _not_ imprimer un 'float', mais un «double». Peut-être que le 'ab_printf()' qui se comporte mal peut-il gérer l'impression d'un 'float' brut? Essayer. 'float F = 1./(1.+exp(-1.*a[i))); ab_printf ("x =% f, y =% f \ n", a [i], F); ' – chux