Question

Quel est le moyen le plus simple de tronquer une variable C ++ float ayant une valeur de 0.6000002 sur une valeur de 0.6000 et de la stocker dans la variable?

Était-ce utile?

La solution

Tout d’abord, il est important de savoir que les nombres en virgule flottante sont approximés. Consultez le lien fourni par @Greg Hewgill pour comprendre pourquoi ce problème ne peut pas être totalement résolu.

Mais voici quelques solutions au problème qui répondront probablement à vos besoins:

Probablement la meilleure méthode mais moins efficace:

char sz[64];
double lf = 0.600000002;
sprintf(sz, "%.4lf\n", lf); //sz contains 0.6000

double lf2 = atof(sz);

//lf == 0.600000002;
//lf2 == 0.6000

printf("%.4lf", lf2); //print 0.6000

Le moyen le plus efficace, mais probablement moins précis:

double lf = 0.600000002;
int iSigned = lf > 0? 1: -1;
unsigned int uiTemp = (lf*pow(10, 4)) * iSigned; //Note I'm using unsigned int so that I can increase the precision of the truncate
lf = (((double)uiTemp)/pow(10,4) * iSigned);

Autres conseils

Une bonne référence sur pourquoi cela se trouve peut être trouvée dans Ce que tous les informaticiens devraient savoir sur l’arithmétique en virgule flottante de David Goldberg.

En réalité, ce n'est pas possible. Ce n'est pas une limitation de C ++, mais simplement la façon dont fonctionne la virgule flottante. Pour de nombreuses valeurs, il n'y a pas de représentation précise, vous ne pouvez donc pas simplement tronquer un nombre de chiffres.

Vous pouvez tronquer lorsque vous imprimez avec des chaînes de format printf.

Si vous devez vraiment pouvoir stocker un nombre limité de chiffres, je vous suggère plutôt d'utiliser un type de données à précision fixe.

Je pense que la question qui devrait être posée ici est la suivante: Pourquoi avez-vous besoin qu'il soit tronqué?

Si c'est pour comparer des valeurs, vous devriez peut-être envisager d'utiliser le test epsilon. (avec une valeur de tolérance supplémentaire, dans votre cas, car il semble être beaucoup plus grand que le epsilon généralement accepté).

Si vous souhaitez simplement l'imprimer sous la forme 0.6000, utilisez les méthodes suggérées par d'autres personnes.

roundf(myfloat * powf(10, numDigits)) / powf(10, numDigits);

Par exemple, dans votre cas, vous tronquez trois chiffres (numDigits). Vous utiliseriez:

roundf(0.6000002 * 1000) / 1000
// And thus:
roundf(600.0002) / 1000
600 / 1000
0.6

(Vous stockerez probablement le résultat de powf quelque part, puisque vous l'utilisez deux fois.)

En raison de la manière dont les flottants sont normalement stockés sur les ordinateurs, il y aurait probablement des inexactitudes. C’est ce que vous obtenez pour utiliser des flotteurs, cependant.

Utilisez ceci:

floor(0.6000002*10000)/10000

Pour C ++ 11, vous pouvez utiliser std::round défini dans l'en-tête <cmath>:

auto trunc_value = std::round(value_to_trunc * 10000) / 10000;

Voici une fonction utilisant les conseils donnés dans d'autres réponses et un exemple d'utilisation:

#include <iostream>
#include <cmath>

static void Truncate(double& d, unsigned int numberOfDecimalsToKeep);

int main(int, char*[])
{

  double a = 1.23456789;
  unsigned int numDigits = 3;

  std::cout << a << std::endl;

  Truncate(a,3);

  std::cout << a << std::endl;

  return 0;
}

void Truncate(double& d, unsigned int numberOfDecimalsToKeep)
{
    d = roundf(d * powf(10, numberOfDecimalsToKeep)) / powf(10, numberOfDecimalsToKeep);
}

Semblable à d’autres réponses, MAIS vous ne devez pas oublier que round, floor et trunc sont différents par définition. Voir la définition et l'exemple de sortie suivants:

http://www.cplusplus.com/reference/cmath/trunc/

Dans ce cas, nous devons analyser avec une précision de 4 décimales et éliminer les décimales non significatives:

trunc(valueToTrunc*10000)/10000

ou

value = (double)((int)(valueToTrunc*10000))/(double)10000
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top