-2

C++ ofrece varias formas de convertir float a string pero todas son de muy mala calidad:

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>


int main(int argc, char *argv[]) {
    
    
    std::string numberstring;
    
    double number=3.141592653579;
    
    
    //usando la funcion to_string para convertir numero a cadena
    std::cout << std::to_string(number) << std::endl;
    
    
    //usando setprecision y flujo para cambiar el numero de decimales
    std::ostringstream contenedorflujo;
    contenedorflujo << std::setprecision(15)<< number ;
    
    numberstring = contenedorflujo.str();
    
    
    std::cout << numberstring << std::endl;
    
    return 0;
}

salida:

3.141592
3.141592653579

La primera función to_string solo muestra 6 decimales y la otra forma que consiste en usar setpresicion y un flujo es muy lenta e incomoda de usar.

Entonces por esas razones quiero mi crear mi propia función que convierta números decimales a flotantes y viceversa en C++, el problema es que no entiendo la explicación que esta en la Wikipedia sobre el formato de coma flotante estándar:

introducir la descripción de la imagen aquí

Alguien puede explicarme con un ejemplo de como funciona el algoritmo y yo me encargo de escribirlo formalmente en código.

JosephGen
  • 301
  • 1
  • 9
  • No pierdas el tiempo implementando tu propia conversión de float a string. No va a ser mejor que la que te viene en la librería. Los problemas de precisión están ya en el propio formato binario y no en su conversión a string. Y no tienen solución salvo que cambies a otro formato binario de representación (coma fija, por ejemplo), lo que obliga a redefinir cómo se hacen todas las operaciones. Probablemente haya librerías que te lo den ya hecho (pero serán más lentas que usar IEEE-754 porque éste está soportado en el hardware de la CPU) – abulafia Apr 14 '21 at 08:31
  • Ya encontré muchos tutoriales en YouTube sobre como convertir números decimales a codificación IEEE-754 y es mucho mas fácil de lo que parece. Estaré subiendo el código cuando lo tenga listo y de esa manera le sirva a alguien mas. – JosephGen Apr 15 '21 at 03:09
  • Hay muchos canales de YouTube en español que explican la codificación https://www.youtube.com/watch?v=HcjXH9WGmAU – JosephGen Apr 15 '21 at 05:31
  • Por supuesto, el tema no es si es fácil o difícil implementar una conversión de IEEE a string. El tema es que aunque lo hagas no vas a ganar más precisión debido al propio formato IEEE. Es más, podría decirse de forma general que tampoco es culpa del formato, cualquier formato en el que el dato tenga un tamaño prefijado (por ejemplo, 64 bits) tendría ese problema. – abulafia Apr 15 '21 at 06:33
  • Puedes diseñar un formato especializado en números muy pequeños, o bien otro especializado en números muy grandes. El punto flotante es una solución intermedia que permite guardar tanto números muy pequeños (usando exponente negativo) como muy grandes (usando exponente positivo). En ambos casos habrá un error al ser la parte mantisa finita, pero la idea es que el error _relativo_ sea el mismo en números pequeños que en grandes. – abulafia Apr 15 '21 at 06:36

1 Answers1

1

C++ ofrece varias formas de convertir float a string pero todas son de muy mala calidad

Si piensas que puedes la salida es mala es porque no tienes demasiada idea acerca del funcionamiento de los números en coma flotante.

Al pasar a binario, la parte entera de un número y la parte decimal se comportan de forma muy diferente:

  • La parte entera consumirá un número de bits proporcional al número de dígitos de dicha parte entera
  • La parte decimal tiene muchas posibilidades de ocupar un número ingente de bits independientemente de cuántos decimales tenga el número

Si resulta que tienes que meter un número potencialmente infinito de bytes en un espacio finito ¿Cómo lo haces? Bien, sencillamente no puedes. Estás obligado a perder información para poder encajar el número en su hueco... y esto es justamente lo que pasa.

Para que te hagas una idea, un dato de tipo float tiene una precisión de 6 dígitos, es decir, para cualquier valor que almacenes en dicho float, solo deberías prestar atención a los primeros 6 dígitos... el resto los puedes considerar basura o no confiables. En el caso del double, son 12 los dígitos representativos.

Así pues, al perder información, pierdes necesariamente precisión y eso lleva a que obtengas esos resultados que calificas como pésimos... para mejorar la precisión tienes dos opciones:

  • Creas un tipo nuevo que ocupe más bytes (o encuentras una forma de evitar que los números decimales puedan ocupar infinitos bytes)
  • Almacenas el número en un string y creas funciones para operar con números decimales en formato cadena de texto

Para más información te sugiero leer este otro hilo: ¿Por qué mis programas no pueden hacer cálculos aritméticos correctamente?

la otra forma que consiste en usar setpresicion y un flujo es muy lenta e incomoda de usar

Lo de lenta, concepto relativo, será porque tienes sincronizadas las IO de C++ con las heredadas de C. Para desincronizarlas (momento a partir del cual se recomienda encarecidamente no mezclaras) y que la IO de C++ sea efectivamente más rápida que la de C basta con escribir esta línea:

std::ios::sync_with_stdio(false);

Lo de engorrosa ... es otro concepto relativo. Si es algo que vas a usar mucho quizás te interese encapsular ese código en una función y dejarlo configurable a tu gusto.

eferion
  • 49,291
  • 5
  • 30
  • 72