web-dev-qa-db-fra.com

Résultats mathématiques multi-lignes différents de ceux d'une seule ligne

J'avais un problème avec certains calculs en virgule flottante et j'ai constaté que si je fais mes calculs sur une ligne, je reçois -0 passé à tan (), et si je le fais sur deux lignes, je reçois 0 à tan () Regarde:

float theta = PI / 2.f;
float p = (PI / 2.f) - theta;
float result = tan(p);

Ce qui précède, p = -0, résultat = -4,37 ...

float theta = PI / 2.f;
float p = PI / 2.f;
p -= theta;
float result = tan(p);

Le ci-dessus, p = 0, résultat = 0.

Quelqu'un peut-il expliquer la différence? Je suppose que le résultat de tan () est dû à -0, bien que je ne trouve rien sur Google qui explique pourquoi. Pourquoi le même calcul exact sur plusieurs lignes donne-t-il une réponse différente?

Merci

7
user2278611

C'est probablement à cause du type de PI .

Si vous utilisez double, il deviendra flottant et le résultat .__ sera comme vous venez de le représenter.

Mais si PI est float, les deux scénarios de test sont égaux.

5
Naor Tedgi

Ce que @Naor dit est probablement correct. mais j'aimerais ajouter quelque chose.

Vous n'obtenez probablement pas -4.37xx mais -4.37xxxe-xx qui est un assez petit nombre négatif.

Puisque vous pouvez toujours obtenir des erreurs en calcul en virgule flottante. Je dirais qu'il n'est pas nécessaire de changer votre code. Les deux coups sont corrects.

4
apple apple

Donc, voici ce qui se passe, à mon avis:

Dans les deux exemples, PI est une définition, probablement définie comme suit:

#define 3.14 //and some more digits

En C++, un nombre comme celui-ci est traité comme un double.

Après le prétraitement, cette expression:

PI / 2.0f

sera traité comme une valeur double. Cela signifie que cette ligne cache une autre opération:

float theta = PI / 2.f;

qui est une conversion double en float, qui perd définitivement de la précision dans ce cas.

Dans le premier exemple, cela se produit également ici:

float p = (PI / 2.f) - theta;

mais seulement après avoir évalué l'expression entière. Notez que lors de cette évaluation, (PI / 2.f) sera toujours le double, mais theta sera une valeur convertie de flottant à double, ce qui explique la légère différence de résultat entre 0.0.

Dans votre dernier exemple, vous avez d'abord converti (PI / 2.f) en float:

float p = PI / 2.f;

pour soustraire theta de type float dans la ligne suivante. Ce qui doit aboutir à 0.0, ce qui rend probablement le compilateur optimisé de toute façon; ).

0
Michał Łoś