2009-06-18 13 views
6

Tengo un problema y no puedo resolverlo. Necesito ayuda de los gurús. Aquí es código de ejemplo: -C++: ¿Cómo convertir de flotador a cadena sin redondeo, truncamiento o relleno?

float f=0.01f; 
printf("%f",f); 

, comprobamos si el valor en la variable durante la depuración f contiene '0,0099999998' valor y la salida de printf es 0,010000.

a. ¿Hay alguna manera de que podamos forzar al compilador a asignar los mismos valores a la variable de tipo flotante?

b. Quiero convertir float a string/character array. ¿Cómo es posible que solo y exactamente el mismo valor se convierta en matriz de cadena/caracteres? Quiero asegurarme de que no se hayan rellenado los ceros, que no se hayan rellenado los valores no deseados, que no haya cambios en los dígitos como en el ejemplo anterior.

Respuesta

2

Echa un vistazo a este C++ reference. Específicamente la sección de precisión:

float blah = 0.01; 
printf ("%.2f\n", blah); 
+0

Creo que tiene problemas con flotadores no dobles – Aamir

+0

jeje ... eso es genial. Me imagino que el voto negativo original puede haber sido debido a mi primera respuesta muy escueta (sin código fuente), y lo suficientemente justo también;). – RedBlueThing

+0

También podría ser porque ignoré todo el tema de la representación del punto flotante y contesté la pregunta en un nivel bastante superficial. – RedBlueThing

2

Hay incontables números reales.

sólo hay un número finito de valores que los tipos de datos, floatdouble, y long double pueden tomar.

Es decir, habrá innumerables números reales que no se pueden representar exactamente utilizando esos tipos de datos.

6

Es imposible representar con precisión un número decimal base 10 usando la base 2 valores, a excepción de un número muy pequeño de valores (tal como 0,25). Para obtener lo que necesita, debe pasar de los tipos integrados flotantes/dobles a algún tipo de paquete de números decimales.

1

La razón de que el depurador le está dando un valor diferente está bien explicado en el post de Mark Ransom.

En cuanto a la impresión de un flotador y sin rodeo, truncamiento y con una precisión más completa, se le falta el especificador de precisión - precisión predeterminada para printf es típicamente 6 dígitos fraccionarios.

intentar lo siguiente para obtener una precisión de 10 dígitos:

float amount = 0.0099999998; 
printf("%.10f", amount); 

Como nota al margen, una forma más de C++ (frente a C-estilo) de hacer las cosas es con cout:

float amount = 0.0099999998; 
cout.precision(10); 
cout << amount << endl; 
0

usted tendría que consultar a sus estándares de la plataforma para determinar cómo determinar mejor el formato correcto, lo que se necesita para que se muestre como a * b^C, donde 'a' es el componente integral que mantiene el signo, 'b' es implementación definida (Probablemente fijada por un estándar), y 'C' es el exponente utilizado para ese número.

Como alternativa, puede simplemente mostrarlo en hexadecimal, sería no significan nada para un ser humano, sin embargo, y aún sería binario para todos los propósitos prácticos. (! Y así como portátiles)

0

Para responder a su segunda pregunta:

que es posible representar con exactitud y sin ambigüedades los flotadores como cadenas. Sin embargo, esto requiere una representación hexadecimal. Por ejemplo, 1/16 = 0.1 y 10/16 es 0.A.

con flotadores hexagonales, se puede definir una representación canónica.Yo personalmente usaría un número fijo de dígitos que representan la cantidad subyacente de bits, pero también podría decidir quitar los ceros finales. No hay confusión posible en que los dígitos finales son cero.

Dado que la representación es exacta, las conversiones son reversibles: f==hexstring2float(float2hexstring(f))

3

usted podría utilizar boost::lexical_cast de esta manera:

float blah = 0.01; 
string w = boost::lexical_cast<string>(blah); 

variable w contendrá valor de texto ,00999999978. Pero no puedo ver cuando realmente lo necesitas.

Se prefiere utilizar boost::format para un formato de flotación preciso como cadena. El código siguiente muestra cómo hacerlo:

float blah = 0.01; 
string w = str(boost::format("%d") % blah); // w contains exactly "0.01" now 
0

para (b), se puede hacer

std::ostringstream os; 
os << f; 
std::string s = os.str(); 
1

Igualmente, se puede utilizar el stdlib.h, en el que hay sprintf, ecvt y fcvt funciones (o al menos, debería haber!).

int sprintf(char* dst,const char* fmt,...); 

char *ecvt(double value, int ndig, int *dec, int *sign); 

char *fcvt(double value, int ndig, int *dec, int *sign); 

sprintf devuelve el número de caracteres que escribió a la cadena, por ejemplo

float f=12.00; 
char buffer[32]; 
sprintf(buffer,"%4.2f",f) // will return 5, if it is an error it will return -1 

ecvt y fcvt caracteres de retorno a static char * lugares que contienen la terminación nula representaciones decimales de los números, sin punto decimal, el número más significativo primero, el desplazamiento del punto decimal se almacena en dec, el signo en "signo" (1 = -, 0 = +) ndig es el número de dígitos significativos para almacenar mi. Si dec < 0, tiene que rellenar con -dec zeros pror hasta el punto decimal. Si no está seguro, y no está trabajando en un sistema Windows7 (que no ejecutará los viejos programas DOS3 a veces) busque TurboC versión 2 para Dos 3, todavía hay una o dos descargas disponibles, es un programa relativamente pequeño de Borland que es un pequeño editor/compilación de Dos C/C++ e incluso viene con TASM, el código de máquina de 16 bits compilación 386/486, está cubierto en los archivos de ayuda como muchos otros nuggets útiles de información.

Las tres rutinas están en "stdlib.h", o deberían serlo, aunque he descubierto que en VisualStudio2010 no son estándar, a menudo están sobrecargadas con funciones que tratan con caracteres de tamaño PALABRA y que le piden que use sus propias funciones específicas en cambio ... "tanto para biblioteca estándar", murmuro para mis adentros casi todas y cada una de las veces, "¡Tal vez buscan un mejor diccionario!"

1

En verdad, usar el procesador de coma flotante o coprocesador o la sección del chip en sí (la mayoría ahora están integrados en la CPU), nunca dará resultados matemáticos precisos, pero dan una precisión bastante aproximada, para obtener más resultados precisos, podría considerar definir una clase "DecimalString", que utiliza nybbles como caracteres decimales y símbolos ... e intentar imitar las matemáticas de la base 10 usando cadenas ... en ese caso, dependiendo de cuánto tiempo quiera hacer las cuerdas , incluso podría eliminar la parte del exponente, en conjunto, una cadena 256 puede representar 1x10^-254 hasta 1^+ 255 en decimal recto usando ASCII real, más corto si desea un signo, pero esto puede ser significativamente más lento. Puede acelerar esto invirtiendo el orden de los dígitos, por lo que de izquierda a derecha leen unidades, decenas, cientos, miles ...

Ejemplo simple por ejemplo. "0021" se convierte en 1200 Esto necesitaría "desplazar" hacia la izquierda y derecha para hacer que los decimales se alineen antes de las rutinas, la mejor opción es comenzar con las funciones AGREGAR y SUB, ya que luego se construirán sobre ellos en el MUL y funciones DIV. ¡Si estás en una máquina grande, podrías hacerlos teóricamente el tiempo que tu corazón desee!