Domanda

Qual è il modo più semplice per troncare una variabile C ++ float che ha un valore da 0.6000002 a un valore di 0.6000 e salvarlo nella variabile?

È stato utile?

Soluzione

Innanzitutto è importante sapere che i numeri in virgola mobile sono approssimativi. Vedi il link fornito da @Greg Hewgill per capire perché questo problema non è completamente risolvibile.

Ma qui ci sono un paio di soluzioni al problema che probabilmente risponderanno alle tue esigenze:

Probabilmente il metodo migliore ma meno efficiente:

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

Il modo più efficiente, ma probabilmente meno preciso:

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);

Altri suggerimenti

Un buon riferimento per perché questo accade può essere trovato in Ciò che ogni scienziato informatico dovrebbe sapere sull'aritmetica in virgola mobile di David Goldberg.

Realisticamente non è possibile. Non è una limitazione C ++, ma solo il modo in cui funziona in virgola mobile. Per molti valori non ci sono rappresentazioni precise, quindi non puoi semplicemente troncare a un numero di cifre.

È possibile troncare quando si stampa utilizzando stringhe di formato printf.

Se devi davvero essere in grado di memorizzare solo un numero limitato di cifre, ti suggerisco di utilizzare invece un tipo di dati a precisione fissa.

Penso che la domanda che dovrebbe essere posta qui sia: Perché ne hai bisogno troncato?

Se è per il confronto tra valori, forse dovresti prendere in considerazione l'uso del test epsilon. (con un valore di tolleranza extra, nel tuo caso, poiché sembra essere molto più grande di epsilon generalmente accettato).

Se vuoi solo stamparlo come 0.6000, usa i metodi suggeriti da altri.

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

Ad esempio, nel tuo caso stai troncando tre cifre (numDigits). Dovresti usare:

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

(Probabilmente dovresti archiviare il risultato di Powf da qualche parte, dal momento che lo stai usando due volte.)

A causa del modo in cui i float sono normalmente memorizzati sui computer, probabilmente ci sarebbero imprecisioni. Questo è quello che ottieni usando i float.

Usa questo:

floor(0.6000002*10000)/10000

Per C ++ 11 è possibile utilizzare std::round definito nell'intestazione <cmath>:

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

Ecco una funzione che utilizza i consigli in altre risposte e un esempio del suo utilizzo:

#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);
}

Simile ad altre risposte, MA non dimenticare che round, floor e trunc sono diversi per definizione. Vedi la definizione e l'esempio di output di quanto segue:

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

In questo caso dobbiamo trucare con una precisione di 4 decimali e sbarazzarci di decimali non significativi:

trunc(valueToTrunc*10000)/10000

o

value = (double)((int)(valueToTrunc*10000))/(double)10000
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top