1

Necesitaría saber si hay alguna forma de mejor (o especificar) la precisión de la función atof. Por supuesto mi objetivo es pasar un string a float. Actualmente lo estoy haciendo de esta manera:

char buffer[]={"3435.68209"};
float resultado;

resultado = atof(buffer);

Pero el valor final luego de la conversión me da: 3435.68213

Entiendo perfectamente el por que de ese "error" y el funcionamiento de los float, pero el sistema que estoy realizando tiene que ser muy preciso y esa diferencia no es aceptable.

¿Hay alguna manera de especificar o mejorar la precisión de atof?

¿Hay alguna otra función para reemplazarlo?

¿Conocen algun otro metodo para pasar de string a float con un 100% de precisión que no sea utilizando una función?

Edito para agregar mas info:

En mi aplicación el valor original en el string siempre va a tener como maximo 5 digitos antes del punto decimal y 6 digitos luego del punto decimal.

Es decir: XXXXX.YYYYYY (puede tener menos en ambos casos, pero jamás mas)

eferion
  • 49,291
  • 5
  • 30
  • 72
cventu
  • 381
  • 4
  • 16
  • 1
    Échale un vistazo a [esta pregunta](http://es.stackoverflow.com/questions/29626/asignar-a-un-float-un-literal-de-punto-flotante-sin-sufijo/29651#29651). – PaperBirdMaster Nov 16 '16 at 14:33
  • Gracias, muy interesante la explicación – cventu Nov 16 '16 at 14:40
  • Hay librerías especializadas en número con **precisión arbitraria**. Consulta sobre libmpfi ( http://mpfi.gforge.inria.rf ) – Trauma Nov 16 '16 at 15:46
  • Ah, se me olvidaba. Dependiendo de para que lo quieras, puedes usar número en **punto fijo**, pero no podrás usar la mayoría de las funciones de la biblioteca estandar. – Trauma Nov 16 '16 at 16:25

2 Answers2

3

atof es una función que te devuelve un tipo double. double es un tipo con una precisión superior a float, de hecho lo normal es que dedique el doble de bits a almacenar el número (4 bytes para float y 8 para double).

El problema de los números en coma flotante es que tienen una precisión determinada. En el caso de float suele rondar los 6 dígitos y en el caso de double, 15. De hecho esta información está disponible en float.h:

#include <float.h>
#include <stdio.h>

int main()
{
  printf("Digitos float: %d\n",FLT_DIG);
  printf("Digitos double: %d\n",DBL_DIG);
}

En mi caso este código arroja el siguiente resultado:

Digitos float: 6
Digitos double: 15

Si quieres una precisión superior a la ofertada por FLT_DIG te recomiendo pasarte al tipo double.

Tu código corregido:

char buffer[]={"3435.68209"};
double resultado = atof(buffer);
eferion
  • 49,291
  • 5
  • 30
  • 72
  • Gracias! Efectivamente fue una distracción mía almacenar el resultado de la conversión en un float y no en un double. Adicionalmente, mientras investigaba encontré la función strtod que convierte string a double. Es totalmente equivalente a atof con la diferencia que atof tiene comportamiento indefinido cuando no es posible convertir el valor y strtod contempla el caso de error. Solo comento esto para que pueda servirle a alguien mas en el futuro, pero tu respuesta es perfectamente valida. Gracias! – cventu Nov 16 '16 at 14:39
1

Tan solo como referencia (ya que la respuesta de eferion es válida) puedes configurar el comportamiento de los números en coma flotante mediante la función fesetround. Podría serte útil.

fesetround

Configura la dirección en que se redondea el número en coma flotante al realizar operaciones. Dado que pasar de texto a número es una operación con coma flotante, los diferentes parámetros usados variarán el resultado. Se puede configurar con las siguientes opciones:

  • FE_DOWNWARD: Redondeo a la baja (hacia -∞).
  • FE_TONEAREST: Redondeo hacia el entero más cercano.
  • FE_TOWARDZERO: Redondeo hacia cero.
  • FE_UPWARD: Redondeo al alza (hacia +∞).

Pobando las diferentes configuraciones:

Usando atof de tu número de ejmplo con las diferentes configuraciones obtenemos:

FE_DOWNWARD

  • Original: 3435.68209
  • Resultado: 3435.68213

FE_TONEAREST

  • Original: 3435.68209
  • Resultado: 3435.68188

FE_TOWARDZERO

  • Original: 3435.68209
  • Resultado: 3435.68213

FE_UPWARD

  • Original: 3435.68209
  • Resultado: 3435.68188

Los mejores resultados los obtienes con FE_TOWARDZERO y FE_DOWNWARD que dan un error de 0,00004; pero esto podría cambiar con diferentes números.

PaperBirdMaster
  • 44,474
  • 6
  • 44
  • 82