Para redondear un float
en C, hay 3 <math.h>
funciones para satisfacer la necesidad. Recomendar rintf()
.
float nearbyintf(float x);
Los nearbyint
funciones alrededor de su argumento a un valor entero en formato de punto flotante, utilizando la dirección actual de redondeo y sin elevar la ‘’ excepción de punto flotante ‘inexacta’. C11dr §7.12.9.3 2
o
float rintf(float x);
Los rint
funciones difieren de los nearbyint
funciones (7.12.9.3) solo en que el rint
funciones pueden elevar el '' inexacta' 'excepción de punto flotante si el resultado difiere en valor del argumento. C11dr §7.12.9.4 2
o
float roundf(float x);
Las funciones round
redondas su argumento al valor entero más cercano en formato de punto flotante de redondeo, los casos de reinserción lejos de cero, sin tener en cuenta la dirección de redondeo actual. C11dr §7.12.9.6 2
Ejemplo
#include <fenv.h>
#include <math.h>
#include <stdio.h>
void rtest(const char *fname, double (*f)(double x), double x) {
printf("Clear inexact flag :%s\n", feclearexcept(FE_INEXACT) ? "Fail" : "Success");
printf("Set round to nearest mode:%s\n", fesetround(FE_TONEAREST) ? "Fail" : "Success");
double y = (*f)(x);
printf("%s(%f) --> %f\n", fname,x,y);
printf("Inexact flag :%s\n", fetestexcept(FE_INEXACT) ? "Inexact" : "Exact");
puts("");
}
int main(void) {
double x = 8.5;
rtest("nearbyint", nearbyint, x);
rtest("rint", rint, x);
rtest("round", round, x);
return 0;
}
salida
Clear inexact flag :Success
Set round to nearest mode:Success
nearbyint(8.500000) --> 8.000000
Inexact flag :Exact
Clear inexact flag :Success
Set round to nearest mode:Success
rint(8.500000) --> 8.000000
Inexact flag :Inexact
Clear inexact flag :Success
Set round to nearest mode:Success
round(8.500000) --> 9.000000
Inexact flag :Exact
Qué es débil sobre el código de OP?
(int)(num < 0 ? (num - 0.5) : (num + 0.5))
En caso num
tienen un valor no cerca de la gama int
, los resultados elenco (int)
un comportamiento indefinido.
Cuando num +/- 0.5
da como resultado una respuesta inexacta. Esto es improbable aquí ya que 0.5
es un double
y hace que la adición ocurra con una precisión mayor que float
. Cuando num
y 0.5
tienen la misma precisión, agregar 0.5
a un número puede dar como resultado respuesta numérica redondeada. (Este no es el redondeo de números enteros de la publicación de OP.) Ejemplo: el número justo por debajo de 0,5 debe redondearse a 0 por objetivo de OP, pero num + 0.5
da como resultado una respuesta exacta entre 1.0 y la más pequeña double
apenas inferior a 1.0. Como la respuesta exacta no es representable, esa suma redondea, por lo general, a 1.0, lo que lleva a una respuesta incorrecta. Una situación similar ocurre con grandes números.dilema
de OP sobre "La línea anterior siempre imprime el valor como 4 incluso cuando float num =4.9
." no es explicable como se dijo. Se necesita código/información adicional. Sospecho que OP pudo haber usado int num = 4.9;
.
// avoid all library calls
// Relies on UINTMAX_MAX >= FLT_MAX_CONTINUOUS_INTEGER - 1
float my_roundf(float x) {
// Test for large values of x
// All of the x values are whole numbers and need no rounding
#define FLT_MAX_CONTINUOUS_INTEGER (FLT_RADIX/FLT_EPSILON)
if (x >= FLT_MAX_CONTINUOUS_INTEGER) return x;
// Positive numbers
// Important: _no_ precision lost in the subtraction
// This is the key improvement over OP's method
if (x > 0) {
float floor_x = (float)(uintmax_t) x;
if (x - floor_x >= 0.5) floor_x += 1.0f;
return floor_x;
}
if (x < 0) return -my_roundf(-x);
return x; // x is 0.0, -0.0 or NaN
}
Probado poco - lo hará más adelante cuando tenga tiempo.
Hay muchos tipos diferentes de redondeo: ¿cuál (es) desea usar? Por favor, publique ejemplos del comportamiento deseado. –
Creo que el problema está en otra parte, que definitivamente debería imprimir 5 para una entrada de 4.9. – IVlad
Sí, la conversión de un tipo de punto flotante a un tipo de entero que puede representar un número del signo y la magnitud requeridos debería funcionar simplemente truncando los decimales; este código hace que el ± 0.5 cause que este truncamiento redondee el valor original lejos de cero. – Arkku