Sigo tropezando con los especificadores de formato para la familia de funciones printf (). Lo que quiero es poder imprimir un doble (o flotante) con un número máximo de dígitos después del punto decimal. Si uso:
printf("%1.3f", 359.01335);
printf("%1.3f", 359.00999);
yo obtengo
359.013
359.010
En lugar de lo deseado
359.013
359.01
Alguien puede ayudarme?
Respuestas:
Esto no se puede hacer con los
printf
especificadores de formato normales . Lo más cercano que podría obtener sería:pero ".6" es el ancho numérico total, por lo que
lo rompe.
Lo que puede hacer es colocar
sprintf("%.20g")
el número en un búfer de cadena y luego manipular la cadena para que solo tenga N caracteres más allá del punto decimal.Suponiendo que su número está en la variable num, la siguiente función eliminará todos los
N
decimales menos los primeros , luego eliminará los ceros finales (y el punto decimal si fueran todos ceros).Si no está satisfecho con el aspecto de truncamiento (que se convertiría
0.12399
en en0.123
lugar de redondearlo0.124
), puede utilizar las funciones de redondeo que ya proporcionaprintf
. Solo necesita analizar el número de antemano para crear dinámicamente los anchos, luego usarlos para convertir el número en una cadena:En
nDecimals()
este caso, el objetivo es calcular correctamente los anchos de campo y luego formatear el número usando una cadena de formato basada en eso. El arnés de pruebamain()
muestra esto en acción:Una vez que tenga el valor redondeado correctamente, puede volver a pasarlo
morphNumericString()
para eliminar los ceros finales simplemente cambiando:dentro:
(o llamando
morphNumericString
al final denDecimals
pero, en ese caso, probablemente combinaría los dos en una función), y terminas con:fuente
.
En algunos lugares, el lugar decimal es en realidad una,
coma.atof
que devuelva el mismo valor.0.10000000000000000555
será0.1
cuando se elimine. El problema puede surgir si tiene un valor ligeramente inferior, como si la representación más cercana de42.1
fue42.099999999314159
. Si realmente quisiera manejar eso, entonces probablemente necesitaría redondear en función del último dígito eliminado en lugar de truncar.printf
funciones similares, ya que ya admiten parámetros dinámicos (*
carácter especial): por ejemplo,printf("%*.*f", total, decimals, x);
genera un número con la longitud total del campo y los decimales especificados dinámicamente.Para deshacerse de los ceros finales, debe usar el formato "% g":
Después de aclarar un poco la pregunta, la supresión de ceros no es lo único que se preguntó, sino que también se requirió limitar la salida a tres lugares decimales. Creo que eso no se puede hacer solo con cadenas de formato sprintf. Como señaló Pax Diablo , se requeriría manipulación de cuerdas.
fuente
Me gusta la respuesta de R. modificada ligeramente:
'1000' determina la precisión.
Potencia al redondeo de 0,5.
EDITAR
Ok, esta respuesta fue editada varias veces y perdí la noción de lo que estaba pensando hace unos años (y originalmente no cumplía con todos los criterios). Entonces, aquí hay una nueva versión (que llena todos los criterios y maneja los números negativos correctamente):
Y los casos de prueba:
Y el resultado de las pruebas:
Ahora, se cumplen todos los criterios:
Desafortunadamente, esta respuesta es de dos líneas, ya
sprintf
que no devuelve la cadena.fuente
Busco en la cadena (comenzando más a la derecha) el primer carácter en el rango
1
a9
(valor ASCII49
-57
) luegonull
(establecido en0
) cada carácter a la derecha - ver a continuación:fuente
¿Qué pasa con algo como esto (puede haber errores de redondeo y problemas de valor negativo que necesitan depuración, se deja como un ejercicio para el lector):
Es un poco programático, pero al menos no te obliga a manipular cadenas.
fuente
Una solución simple pero que hace el trabajo, asigna una longitud y precisión conocidas y evita la posibilidad de pasar al formato exponencial (que es un riesgo cuando se usa% g):
Agregue o elimine "más" si desea un máximo de 2 decimales; 4 decimales; etc.
Por ejemplo, si desea 2 decimales:
Si desea especificar el ancho mínimo para mantener los campos alineados, incremente según sea necesario, por ejemplo:
También puede convertir eso en una función en la que pase el ancho deseado del campo:
fuente
d = 0.0001
: luegofloor(d)
es0
, por lo que la diferencia es mayor que 0.000001, por lo queDoubleEquals
es falso, por lo que no usará el"%.0f"
especificador: verá ceros al final de"%*.2f"
o"%*.3f"
. Entonces no responde la pregunta.Encontré problemas en algunas de las soluciones publicadas. Reuní esto según las respuestas anteriores. Parece funcionar para mí.
fuente
Algunas de las soluciones más votadas sugieren el
%g
especificador de conversión deprintf
. Esto es incorrecto porque hay casos en los%g
que producirá notación científica. Otras soluciones usan matemáticas para imprimir el número deseado de dígitos decimales.Creo que la solución más fácil es usarla
sprintf
con el%f
especificador de conversión y eliminar manualmente los ceros finales y posiblemente un punto decimal del resultado. Aquí hay una solución C99:Tenga en cuenta que los caracteres utilizados para los dígitos y el separador decimal dependen de la configuración regional actual. El código anterior asume una configuración regional C o inglés de EE. UU.
fuente
Aquí está mi primer intento de respuesta:
Errores conocidos: posible desbordamiento del búfer según el formato. Si "." está presente por otra razón que% f puede ocurrir un resultado incorrecto.
fuente
¿Por qué no hacer esto?
fuente
Ligera variación de arriba:
Codifique aquí:
Todavía tiene potencial de desbordamiento, así que tenga cuidado; P
fuente
Yo diría que deberías usar
printf("%.8g",value);
Si lo usa
"%.6g"
, no obtendrá la salida deseada para algunos números como 32.230210, debería imprimirse32.23021
pero imprime32.2302
fuente
Su código se redondea a tres lugares decimales debido al ".3" antes de la f
Por lo tanto, si redondeó la segunda línea a dos lugares decimales, debe cambiarla a esto:
Ese código generará los resultados deseados:
* Tenga en cuenta que esto es asumiendo que ya lo tiene imprimiendo en líneas separadas, de lo contrario, lo siguiente evitará que se imprima en la misma línea:
El siguiente código fuente del programa fue mi prueba para esta respuesta
fuente