2009-09-08 5 views
4

J'ai un code écrit en C qui est destiné à un microcontrôleur 16 bits. Le code fait essentiellement beaucoup d'arithmétique en virgule flottante. L'arithmétique fonctionne bien jusqu'à ce que le résultat soit positif, mais en cas de soustraction, si le résultat attendu est négatif, j'obtiens un zéro.Soustraction de virgule flottante dans les résultats C zéro

result = 0.005 - 0.001;  Is correctly computed as 0.004 
result = 0.001 - 0.005;  Is always zero. 

Pourquoi un tel comportement existe-t-il pour float?

+4

Peut-être avez-vous un 'float non signé '. :) –

Répondre

5

Intéressant. Cela pourrait très bien être une faute dans le logiciel à virgule flottante. Les systèmes embarqués incluent souvent des virgules flottantes en option afin de réduire la taille du code.

Je ne suis pas sûr que ce soit le problème ici, même si votre première déclaration fonctionne.

Que se passe avec:

result = 0.005 - 0.001; 
result = -result; 

result = 0.002 - 0.001; 
result = 0.002 - 0.002; 
result = 0.002 - 0.003; 

result = 0.001 - 0.002; 
result = 0.001 - 0.003; 
result = 0.001 - 0.004; 

L'idée est de recueillir ici des informations utiles à ce qui pourrait être le cause, une chose commune à faire en médecine légale. Les résultats de ces calculs seront probablement utiles pour déterminer le problème réel.

En fonction de vos résultats dans les commentaires:

result = 0.005 - 0.001; // 0.004 
result = -result;  // 0.000 
result = 0.002 - 0.001; // 0.001 
result = 0.002 - 0.002; // 0.000 
result = 0.002 - 0.003; // 0.000 
result = 0.001 - 0.002; // 0.000 
result = 0.001 - 0.003; // 0.000 
result = 0.001 - 0.004; // 0.000 

Il ressemble à votre bibliothèque de virgule flottante a une grave lacune. Deux autres questions:

  • Comment allez-vous imprimer les résultats (nous montrer le code réel )?
  • Quel microcontrôleur et environnement de développement utilisez-vous?

Il peut y avoir un problème avec la façon dont vous imprimez ou cela peut constituer une limitation de votre environnement. Ajit, je pense que vous allez vraiment devoir nous donner du code pour vous aider. Pas nécessairement votre vrai code (votre souci de libérer le vrai code est compris), juste quelques-uns qui démontrent le problème.

Basé sur certains de vos commentaires, à savoir:

Adriaan, le type de données « résultat » est de flotteur, qui est une représentation de 32 bits (simple). J'ai CAN comme interface système, et donc je multiplie le résultat par 1000 pour l'envoyer sur le bus CAN. S'il se trouve qu'il s'agit d'un nombre négatif, comme -0,003, j'attends FF FD dans le message CAN. Je n'ai pas de débogueur.

Je ne suis pas sûr de comprendre totalement, mais je vais essayer.

Vous avez un flotteur 32 bits, par exemple, -0,003 et vous multipliez par 1000 et le mettre dans un entier (0xFFFD est le 16 bits deux représentation de complément de -3).Alors qu'est-ce qui se passe lorsque vous exécutez quelque chose comme le code suivant:

int main(void) { 
    float w = -0.003; 
    int x = (int)(w * 1000); 
    int y = -3; 
    int z = -32768; 
    // Show us you code here for printing x, y and z. 
    return 0; 
} 

La raison pour laquelle je veux que vous tester un entier est qu'il peut avoir rien à voir avec flotteurs du tout. Il se peut que la valeur float soit parfaitement correcte, mais il y a un problème avec la façon dont vous l'imprimez (la méthode CAN).

Si "CAN" est une sorte d'interface série, il se peut qu'il y ait une restriction sur les octets que vous êtes autorisé à envoyer à travers. Je peux envisager un scénario où les octets élevés sont utilisés comme marqueurs de paquets, de sorte que FF peut effectivement terminer le message prématurément. C'est pourquoi je veux aussi que vous testiez -32768 (0x8000).

Il est difficile de croire que STMicroelectronics produirait un tel système d'exécution braindead qu'il ne pouvait pas gérer les flotteurs négatifs. Il me semble beaucoup plus probable que l'information soit corrompue ailleurs (par exemple, le processus d '«impression», quel qu'il soit).

+0

Voici les observations: résultat = 0,005 - 0,001; = 0,004 résultat = -result; = 0 résultat = 0,002 - 0,001; = 0,001 résultat = 0,002 - 0,002; = 0 résultat = 0,002 - 0,003; = 0 résultat = 0,001 - 0,002; = 0 résultat = 0,001 - 0,003; = 0 résultat = 0,001 - 0,004; = 0 Egalement résultat = 0,01 - 0,04; = 0 résultat = 0,01 - 0,05; = 0 –

+1

Pax, C'est un contrôleur de la série ST10. –

+1

Hey Pax, J'ai obtenu le correctif. Comme vous l'avez dit, il n'y a aucun problème avec l'arithmétique en virgule flottante.Le problème réside dans la conversion de float négatif en entier. Pour ST10, flotteur w = -0,003; int x = (int) (w * 1000); dans Zero. La méthode correcte est la suivante: 1. float w = -0.003; flotteur a = -w; 2. int b = (int) (a * 1000); 3. int c = -b; Ainsi, "C" aurait l'entier signé correspondant à la valeur flottante négative. Merci pour votre aide !!!! Salutations :-) –

0

Le microcontrôleur dispose-t-il de matériel pour le virgule flottante? Probablement pas; les microcontrôleurs ne le font généralement pas. Donc, cela pourrait être un bug ou une limitation dans l'implémentation logicielle de l'arithmétique en virgule flottante. Recherchez la documentation et/ou lisez la source si vous l'avez.

+0

Non, le micro n'a pas le harware à virgule flottante. Mais à la place, il a des bibliothèques à virgule flottante. De certains projets précédents, il n'y a pas d'erreur dans le fichier .lib. –

0

Est-il possible que vous essayiez d'imprimer le résultat de 0,001 - 0,005 comme champ de 5 caractères? Si c'est le cas, le résultat sera arrondi à 0.0.

+0

Merci Stephen mais je multiplie le résultat par 1000 pour le voir comme un nombre entier. –

0

Pouvez-vous fournir plus de contexte? Dans cet exemple, l'évaluation est correctement effectuée par le compilateur car les deux constantes sont connues au moment de la compilation. Quel est le type de 'résultat'? (c'est-à-dire IEEE-754 la moitié ou le simple ou le double?) Comment évaluez-vous ceci? En utilisant un débogueur, if-statement ou avec un printf? La raison pour laquelle je pose cette question est parce qu'il peut y avoir un hareng rouge. Par exemple, si vous formatez incorrectement avec printf, vous ne verrez peut-être pas le signe moins. Lorsque vous jetez un oeil à la représentation binaire (c'est-à-dire par printf ("% lx", résultat) si elle est de 32 bits) et vérifiez le bit de signe.

+0

Adriaan, le type de données pour "résultat" est de flottante, c'est-à-dire une représentation de 32 bits (unique). J'ai CAN comme interface système et donc je multiplie le résultat par 1000 pour envoyer ti sur le CAN. S'il se trouve qu'il y a un nombre négatif comme -0.003 alors j'attends FF FD dans le message CAN. Je n'ai pas de débogueur. –

0

Ce n'est pas une chose en soi C, il est donc bas aux choses que vous ne l'avez pas dit: -

  • Controller (ST10 Apparemment)
  • compilateur (? Logiciel cosmique Si oui est conforme aux normes)
  • bibliothèque à virgule flottante (du compilateur?)
  • le programme (Shortest programme complet qui démontre qu'il serait bon.)

Pourrait-il être votre conversion de virgule flottante à un int que vous n'avez pas montré?

+0

Ne semble pas parce que le même code fonctionne quand le résultat est positif. Je ne peux pas partager le programme avec vous en raison de problèmes IP. Désolé. –

+0

Sûrement vous pourriez faire une forme courte cependant? Je pense que d'autres parties du code sont plus susceptibles d'être le problème. Votre connaissance de ce qui est dans "résultat" n'est déduite qu'après tout. –

+0

int x = (int) (w * 1000); résultats dans zéro Essayez 1000.0 il fait une conversion implicite traitant 1000 comme const int. –

Questions connexes