to_string - float to string c++
¿Cómo ''cout'' el número correcto de lugares decimales de un valor doble? (9)
Debe usar setiosflags(ios::fixed)
y setprecision(x)
.
Por ejemplo, cout << setiosflags(ios::fixed) << setprecision(4) << myNumber << endl;
Además, no te olvides de #include <iomanip.h>
.
Necesito ayuda para mantener la precisión de un double
. Si asigno un literal a un doble, el valor real se truncó.
int main() {
double x = 7.40200133400;
std::cout << x << "/n";
}
Para el fragmento de código anterior, la salida fue 7.402
¿Hay alguna manera de prevenir este tipo de truncamiento? ¿O hay una manera de calcular exactamente cuántos puntos flotantes para un double
? Por ejemplo, number_of_decimal(x)
daría 11, ya que la entrada es desconocida en tiempo de ejecución, así que no puedo usar setprecision()
.
Creo que debería cambiar mi pregunta a: Cómo convertir un doble en una cadena sin truncar los puntos flotantes. es decir
#include <iostream>
#include <string>
#include <sstream>
template<typename T>
std::string type_to_string( T data ) {
std::ostringstream o;
o << data;
return o.str();
}
int main() {
double x = 7.40200;
std::cout << type_to_string( x ) << "/n";
}
El resultado esperado debería ser 7.40200 pero el resultado real fue 7.402. Entonces, ¿cómo puedo solucionar este problema? ¿Alguna idea?
Debido al hecho de que el float
y el double
están almacenados internamente en binario, el literal 7.40200133400
realidad representa el número 7.40200133400000037653398976544849574565887451171875
... ¿Cuánta precisión realmente quieres? :-)
#include <iomanip>
int main()
{
double x = 7.40200133400;
std::cout << std::setprecision(51) << x << "/n";
}
Y sí, este programa realmente imprime 7.40200133400000037653398976544849574565887451171875!
Hagamos una solicitud análoga: después de inicializar un número entero con 001, querrá imprimirlo con los ceros a la izquierda. Esa información de formato simplemente nunca se almacenó.
Para comprender mejor el almacenamiento de punto flotante de doble precisión, consulte el estándar IEEE 754.
La única respuesta a esto que he encontrado es que no hay forma de hacerlo (¡como en el cálculo de los decimales) correctamente! La razón principal de esto es que la representación de un número puede no ser lo que esperas, por ejemplo, 128.82, parece lo suficientemente inocua, sin embargo, su representación real es 128.8199999999 ... ¿cómo se calcula el número de decimales allí?
La segunda parte de la pregunta, acerca de cómo conservar los ceros finales en un valor de coma flotante desde la especificación de valor hasta el resultado de salida, no tiene solución. Un valor de punto flotante no retiene la especificación de valor original. Parece que esta parte sin sentido fue agregada por un moderador SO.
Con respecto a la primera y original parte de la pregunta, que interpreto como cómo presentar todos los dígitos significativos de 7.40200133400
, es decir, con un resultado como 7.402001334
, puedes simplemente eliminar los ceros finales de un resultado de salida que incluye solo dígitos confiables en el double
valor:
#include <assert.h> // assert
#include <limits> // std::(numeric_limits)
#include <string> // std::(string)
#include <sstream> // std::(ostringstream)
namespace my{
// Visual C++2017 doesn''t support comma-separated list for `using`:
using std::fixed; using std::numeric_limits; using std::string;
using std::ostringstream;
auto max_fractional_digits_for_positive( double value )
-> int
{
int result = numeric_limits<double>::digits10 - 1;
while( value < 1 ) { ++result; value *= 10; }
return result;
}
auto string_from_positive( double const value )
-> string
{
ostringstream stream;
stream << fixed;
stream.precision( max_fractional_digits_for_positive( value ) );
stream << value;
string result = stream.str();
while( result.back() == ''0'' )
{
result.resize( result.size() - 1 );
}
return result;
}
auto string_from( double const value )
-> string
{
return (0?""
: value == 0? "0"
: value < 0? "-" + string_from_positive( -value )
: string_from_positive( value )
);
}
}
#include<iostream>
auto main()
-> int
{
using std::cout;
cout << my::string_from( 7.40200133400 ) << "/n";
cout << my::string_from( 0.00000000000740200133400 ) << "/n";
cout << my::string_from( 128.82 ) << "/n";
}
Salida:
7.402001334 0.000000000007402001334 128.81999999999999
Puede considerar agregar lógica para el redondeo para evitar largas secuencias de 9, como en el último resultado.
Los dobles no tienen lugares decimales. Tienen lugares binarios. Y los lugares binarios y decimales son inconmensurables (porque log2(10)
no es un número entero).
Lo que estás pidiendo no existe.
Respondiendo a su edición de respuestas: no hay forma de hacer eso. Tan pronto como se asigna un valor a un double
, se pierden los ceros finales (para el compilador / computadora, 0.402, 0.4020 y 0.40200 son el MISMO NÚMERO). La única manera de retener los ceros finales como lo indicó es almacenar los valores como cadenas (o hacer trucos donde se hace un seguimiento de la cantidad de dígitos que le interesan y se formatea exactamente a esa longitud).
Solución usando Boost.Format :
#include <boost/format.hpp>
#include <iostream>
int main() {
double x = 7.40200133400;
std::cout << boost::format("%1$.16f") % x << "/n";
}
Esto produce 7.4020013340000004
.
¡Espero que esto ayude!
std::cout << std::setprecision(8) << x;
Tenga en cuenta que setprecision
es persistente y todos los flotantes siguientes que imprima se imprimirán con esa precisión, hasta que lo cambie a un valor diferente. Si eso es un problema y desea solucionarlo, puede usar un objeto proxy de stringstream
:
std::stringstream s;
s << std::setprecision(8) << x;
std::cout << s.str();
Para obtener más información sobre el formato iostream, consulte la sección de manipuladores de entrada / salida en cppreference.