¿Cómo puedo redondear un valor flotante (como 37.777779) a dos decimales (37.78) en C?
c
floating-point
decimal
Sakib Arifin
fuente
fuente
float
(ydouble
) no son coma flotante decimal, son coma flotante binaria, por lo que redondear a posiciones decimales no tiene sentido. Sin embargo, puede redondear la salida.Respuestas:
Si solo desea redondear el número para fines de salida, la
"%.2f"
cadena de formato es la respuesta correcta. Sin embargo, si realmente desea redondear el valor de coma flotante para un mayor cálculo, algo como lo siguiente funciona:Observe que hay tres reglas de redondeo diferentes que puede elegir: redondear hacia abajo (es decir, truncar después de dos decimales), redondear al más cercano y redondear hacia arriba. Por lo general, desea redondear al más cercano.
Como varios otros han señalado, debido a las peculiaridades de la representación de coma flotante, estos valores redondeados pueden no ser exactamente los valores decimales "obvios", pero estarán muy, muy cerca.
Para obtener más (¡mucho!) Más información sobre el redondeo, y especialmente sobre las reglas de desempate para el redondeo al más cercano, consulte el artículo de Wikipedia sobre el redondeo .
fuente
doubles
también de alguna manera? No parece hacer el trabajo que quiero :( (usandofloor
yceil
).Usando % .2f en printf. Solo imprime 2 puntos decimales.
Ejemplo:
Salida:
fuente
float
rango, ya queval * 100
podría desbordarse.Suponiendo que está hablando de redondear el valor de impresión, la respuesta de Andrew Coleson y AraK es correcta:
Pero tenga en cuenta que si desea redondear el número exactamente a 37.78 para uso interno (por ejemplo, para compararlo con otro valor), entonces esta no es una buena idea, debido a la forma en que funcionan los números de coma flotante: generalmente no desea hacer comparaciones de igualdad para coma flotante, en su lugar use un valor objetivo +/- un valor sigma. O codifique el número como una cadena con una precisión conocida y compárelo.
Vea el enlace en la respuesta de Greg Hewgill a una pregunta relacionada , que también cubre por qué no debe usar coma flotante para los cálculos financieros.
fuente
printf("%.*f", (int)precision, (double)number);
Qué tal esto:
fuente
Si quieres escribir en C-string:
fuente
No hay forma de redondear un
float
a otrofloat
porque el redondeadofloat
puede no ser representable (una limitación de los números de coma flotante). Por ejemplo, supongamos que redondea 37.777779 a 37.78, pero el número representable más cercano es 37.781.Sin embargo, puede "redondear" a
float
mediante una función de cadena de formato.fuente
float
a n decimales y luego esperar que el resultado siempre tenga n decimales. Todavía obtendrá unfloat
, simplemente no el que esperaba.Además, si está utilizando C ++, puede crear una función como esta:
Luego puede generar cualquier doble
myDouble
conn
lugares después del punto decimal con un código como este:fuente
Aún puedes usar:
ejemplo:
fuente
En C ++ (o en C con conversiones de estilo C), puede crear la función:
Entonces
std::cout << showDecimals(37.777779,2);
produciría: 37.78.Obviamente, realmente no necesita crear las 5 variables en esa función, pero las dejo allí para que pueda ver la lógica. Probablemente haya soluciones más simples, pero esto funciona bien para mí, especialmente porque me permite ajustar la cantidad de dígitos después del decimal, según sea necesario.
fuente
Utilice siempre la
printf
familia de funciones para esto. Incluso si desea obtener el valor como flotante, es mejor usarlosnprintf
para obtener el valor redondeado como una cadena y luego analizarlo de nuevo conatof
:Digo esto porque el enfoque que se muestra en la respuesta actualmente más votada y en varias otras aquí, multiplicando por 100, redondeando al entero más cercano y luego dividiendo por 100 nuevamente, tiene fallas de dos maneras:
Para ilustrar el primer tipo de error, la dirección de redondeo a veces es incorrecta, intente ejecutar este programa:
Verás esta salida:
Tenga en cuenta que el valor con el que comenzamos fue menor que 0.015, por lo que la respuesta matemáticamente correcta al redondearlo a 2 decimales es 0.01. Por supuesto, 0.01 no es exactamente representable como un doble, pero esperamos que nuestro resultado sea el doble más cercano a 0.01. Usar
snprintf
nos da ese resultado, pero usarround(100 * x) / 100
nos da 0.02, lo cual está mal. ¿Por qué? Porque100 * x
nos da exactamente 1.5 como resultado. Multiplicar por 100 cambia la dirección correcta para redondear.Para ilustrar el segundo tipo de error - el resultado a veces equivocarse debido a
* 100
y/ 100
no ser verdaderamente inversas entre sí - podemos hacer un ejercicio similar con un número muy grande:Nuestro número ahora ni siquiera tiene una parte fraccional; es un valor entero, solo almacenado con tipo
double
. Entonces, el resultado después de redondearlo debería ser el mismo número con el que comenzamos, ¿verdad?Si ejecuta el programa anterior, verá:
Ups Nuestro
snprintf
método devuelve el resultado correcto nuevamente, pero el enfoque de multiplicar, redondear y luego dividir falla. Esto se debe a que el valor matemáticamente correcto de8631192423766613.0 * 100
,863119242376661300.0
no es exactamente representable como un doble; el valor más cercano es863119242376661248.0
. Cuando divide eso por 100, obtiene8631192423766612.0
un número diferente al que comenzó.Esperemos que sea una demostración suficiente de que el uso
roundf
para redondear a un número de decimales está roto, y que debería usarsnprintf
en su lugar. Si eso te parece un truco horrible, quizás te tranquilice saber que es básicamente lo que hace CPython .fuente
Uso
float roundf(float x)
."Las funciones de redondeo redondean su argumento al valor entero más cercano en formato de punto flotante, redondeando a la mitad los casos desde cero, independientemente de la dirección de redondeo actual". C11dr §7.12.9.5
Dependiendo de su
float
implementación, los números que pueden parecer intermedios no lo son. como punto flotante es típicamente orientado a base 2. Además, redondear con precisión al más cercano0.01
en todos los casos "intermedios" es el más difícil.Aunque "1.115" está "a mitad de camino" entre 1.11 y 1.12, cuando se convierte a
float
, el valor es1.115000009537...
y ya no es "a mitad de camino", sino más cercano a 1.12 y se redondea al más cercanofloat
de1.120000004768...
"1.125" es "mitad de camino" entre 1.12 y 1.13, cuando se convierte a
float
, el valor es exactamente1.125
y es "mitad de camino". Se redondea hacia 1.13 debido a lazos para gobernar incluso y se redondea al más cercanofloat
de1.129999995232...
Aunque "1.135" está "a mitad de camino" entre 1.13 y 1.14, cuando se convierte a
float
, el valor es1.134999990463...
y ya no es "a mitad de camino", sino más cercano a 1.13 y se redondea al más cercanofloat
de1.129999995232...
Si se usa el código
Aunque "1,135" es "a medio camino" entre 1,13 y 1,14, cuando se convierte a
float
, el valor es1.134999990463...
y ya no es "medio-way", pero más cerca de 1.13 pero incorrectamente rondas afloat
de1.139999985695...
debido a la más limitada precisión defloat
vs.double
. Este valor incorrecto puede verse como correcto, dependiendo de los objetivos de codificación.fuente
Hice esta macro para redondear números flotantes. Agréguelo en su encabezado / ser de archivo
Aquí hay un ejemplo:
x es igual a 3.14 :)
fuente
Aquí
n
está el número de decimalesejemplo:
fuente
dval
es enorme 3) el extrañoif
/else
bloque donde haces exactamente lo mismo en cada rama y 4) el uso excesivamente complicado desprintf
para construir el especificador de formato para una segundasprintf
llamada; es más simple usar.*
y pasar el doble valor y el número de decimales como argumentos a la mismasprintf
llamada.Definición de código:
Resultados:
fuente
Permítanme primero intentar justificar mi razón para agregar otra respuesta a esta pregunta. En un mundo ideal, el redondeo no es realmente un gran problema. Sin embargo, en sistemas reales, es posible que deba lidiar con varios problemas que pueden resultar en redondeo que puede no ser lo que espera. Por ejemplo, es posible que esté realizando cálculos financieros donde los resultados finales se redondean y se muestran a los usuarios como 2 lugares decimales; estos mismos valores se almacenan con precisión fija en una base de datos que puede incluir más de 2 decimales (por varias razones; no hay un número óptimo de lugares para guardar ... depende de situaciones específicas que cada sistema debe soportar, por ejemplo, artículos pequeños cuyos precios son fracciones de un centavo por unidad); y, cálculos de coma flotante realizados en valores donde los resultados son más / menos épsilon. He estado enfrentando estos problemas y desarrollando mi propia estrategia a lo largo de los años. No afirmaré que me he enfrentado a todos los escenarios o que tengo la mejor respuesta, pero a continuación hay un ejemplo de mi enfoque hasta ahora que supera estos problemas:
Suponga que 6 decimales se consideran precisión suficiente para los cálculos de flotantes / dobles (una decisión arbitraria para la aplicación específica), utilizando la siguiente función / método de redondeo:
El redondeo a 2 decimales para la presentación de un resultado se puede realizar como:
Para
val = 6.825
, el resultado es6.83
como se esperaba.Para
val = 6.824999
, el resultado es6.82
. Aquí la suposición es que el cálculo resultó exactamente6.824999
y el séptimo lugar decimal es cero.Para
val = 6.8249999
, el resultado es6.83
. El séptimo lugar decimal9
en este caso hace que laRound(val,6)
función dé el resultado esperado. Para este caso, podría haber cualquier número de9
s finales .Para
val = 6.824999499999
, el resultado es6.83
. Redondeando al octavo lugar decimal como primer paso, es decirRound(val,8)
, se ocupa del único caso desagradable por el cual un resultado de coma flotante calculado se calcula6.8249995
, pero se representa internamente como6.824999499999...
.Finalmente, el ejemplo de la pregunta ...
val = 37.777779
da como resultado37.78
.Este enfoque podría generalizarse aún más como:
donde N es la precisión que se debe mantener para todos los cálculos intermedios en flotadores / dobles. Esto también funciona en valores negativos. No sé si este enfoque es matemáticamente correcto para todas las posibilidades.
fuente
Código C simple para redondear un número:
Esto generará:
fuente
... o puedes hacerlo a la antigua usanza sin ninguna biblioteca:
Eso, por supuesto, si desea eliminar la información adicional del número.
fuente
esta función toma el número y la precisión y devuelve el número redondeado
convierte el número de coma flotante en int desplazando el punto a la izquierda y verificando la condición mayor de cinco.
fuente