Pregunta

¿Cuál es la forma más fácil de truncar una variable C ++ float que tiene un valor de 0.6000002 a un valor de 0.6000 y almacenarla nuevamente en la variable?

¿Fue útil?

Solución

Primero es importante saber que los números de coma flotante son aproximados. Consulte el enlace proporcionado por @Greg Hewgill para comprender por qué este problema no es completamente solucionable.

Pero aquí hay un par de soluciones al problema que probablemente satisfarán su necesidad:

Probablemente el mejor método pero menos eficiente:

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

La forma más eficiente, pero probablemente menos precisa:

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

Otros consejos

Una buena referencia para por qué esto sucede se puede encontrar en Lo que todo informático debe saber sobre la aritmética de coma flotante por David Goldberg.

Siendo realistas, eso no es posible. No es una limitación de C ++, sino la forma en que funciona el punto flotante. Para muchos valores no hay representaciones precisas, por lo que no puede simplemente truncar a una cantidad de dígitos.

Puede truncar al imprimir utilizando cadenas de formato printf.

Si realmente necesita poder almacenar solo un número limitado de dígitos, le sugiero que utilice un tipo de datos de precisión fija en su lugar.

Creo que la pregunta que debería hacerse aquí es: ¿Por qué lo necesitas truncado?

Si es para comparar valores, quizás debería considerar usar la prueba epsilon. (con un valor de tolerancia adicional, en su caso, ya que parece ser mucho más grande que el epsilon generalmente aceptado).

Si solo desea imprimirlo como 0.6000, use los métodos que otros han sugerido.

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

Por ejemplo, en su caso está truncando tres dígitos (numDigits). Usarías:

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

(Probablemente almacenarías el resultado de powf en algún lugar, ya que lo estás usando dos veces).

Debido a cómo los flotadores se almacenan normalmente en las computadoras, probablemente habrá imprecisiones. Sin embargo, eso es lo que obtienes por usar flotadores.

Use esto:

floor(0.6000002*10000)/10000

Para C ++ 11 puede usar std::round definido en el encabezado <cmath>:

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

Aquí hay una función que utiliza los consejos de otras respuestas y un ejemplo de su uso:

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

Similar a otras respuestas, PERO no debes olvidar que la ronda, el piso y el trunc son diferentes por definición. Consulte la definición y el ejemplo de salida de lo siguiente:

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

En este caso, necesitamos trucar con una precisión de 4 decimales y deshacernos de decimales no significativos:

trunc(valueToTrunc*10000)/10000

o

value = (double)((int)(valueToTrunc*10000))/(double)10000
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top