round redondear metodo hacia arriba c floating-point ieee-754 c89 floor

c - redondear - math.round java



¿Floor() devuelve algo que sea exactamente representable? (3)

Si el resultado de floor () no es exactamente representable, ¿qué esperas que sea el valor de d? Seguramente si tienes la representación de un número de coma flotante en una variable, entonces, por definición, es exactamente representable, ¿no? Tienes la representación en d ...

(Además, la respuesta de Mehrdad es correcta para las entradas de 32 bits. En un compilador con un doble de 64 bits y un int de 64 bits, tienes más problemas, por supuesto ...)

EDITAR: Quizás quiso decir "el resultado teórico de floor (), es decir, el valor entero más grande menor o igual que el argumento, puede no ser representable como int". Eso es ciertamente cierto. Una forma simple de mostrar esto para un sistema donde int es de 32 bits:

int max = 0x7fffffff; double number = max; number += 10.0; double f = floor(number); int oops = (int) f;

No puedo recordar lo que C hace cuando las conversiones de desbordamiento de punto flotante a entero ... pero va a suceder aquí.

EDITAR: También hay otras situaciones interesantes que considerar. Aquí hay algunos códigos y resultados de C #: me imagino que al menos cosas similares sucederían en C. En C #, el double se define como de 64 bits, por lo que es long .

using System; class Test { static void Main() { FloorSameInteger(long.MaxValue/2); FloorSameInteger(long.MaxValue-2); } static void FloorSameInteger(long original) { double convertedToDouble = original; double flooredToDouble = Math.Floor(convertedToDouble); long flooredToLong = (long) flooredToDouble; Console.WriteLine("Original value: {0}", original); Console.WriteLine("Converted to double: {0}", convertedToDouble); Console.WriteLine("Floored (as double): {0}", flooredToDouble); Console.WriteLine("Converted back to long: {0}", flooredToLong); Console.WriteLine(); } }

Resultados:

Valor original: 4611686018427387903
Convertido en doble: 4.61168601842739E + 18
Piso (como doble): 4.61168601842739E + 18
Convertido de nuevo a largo: 4611686018427387904

Valor original: 9223372036854775805
Convertido en doble: 9.22337203685478E + 18
Piso (como doble): 9.22337203685478E + 18
Convertido de nuevo a largo: -9223372036854775808

En otras palabras:

(long) floor((double) original)

no es siempre lo mismo que original . Esto no debería ser una sorpresa: hay más valores largos que dobles (dados los valores NaN) y muchos dobles no son enteros, por lo que no podemos esperar que todo el tiempo sea exactamente representable. Sin embargo, todos los enteros de 32 bits son representables como dobles.

En C89, floor () devuelve un doble. ¿Está garantizado que lo siguiente funcionará?

double d = floor(3.0 + 0.5); int x = (int) d; assert(x == 3);

Mi preocupación es que el resultado del piso podría no ser exactamente representable en IEEE 754. Así que d obtiene algo como 2.99999, y x termina siendo 2.

Para que la respuesta a esta pregunta sea afirmativa, todos los enteros dentro del rango de un int tienen que ser exactamente representables como dobles, y floor siempre debe devolver ese valor exactamente representado.


Todos los enteros pueden tener una representación de coma flotante exacta si su tipo de punto flotante admite los bits de mantisa requeridos. Dado que el double usa 53 bits para mantisa, puede almacenar todos los int 32 bits exactamente. Después de todo, puedes establecer el valor como mantisa con cero exponente.


Creo que estás un poco confundido acerca de lo que quieres preguntar. floor(3 + 0.5) no es un muy buen ejemplo, porque 3, 0.5 y su suma son todos exactamente representables en cualquier formato de coma flotante del mundo real. floor(0.1 + 0.9) sería un mejor ejemplo, y la verdadera pregunta aquí no es si el resultado del floor es exactamente representable, sino si la inexactitud de los números antes del floor llamada dará como resultado un valor de retorno diferente de lo que cabría esperar , todos los números fueron exactos. En este caso, creo que la respuesta es sí, pero depende mucho de tus números particulares.

Invito a otros a criticar este enfoque si es malo, pero una solución posible podría ser multiplicar su número por (1.0+0x1p-52) o algo similar antes de llamar al floor (quizás sea mejor usar el nextafter ). Esto podría compensar los casos en que un error en el último lugar binario del número hace que caiga justo debajo, en lugar de exactamente en un valor entero, pero no tendrá en cuenta los errores acumulados en varias operaciones. Si necesita ese nivel de estabilidad / exactitud numérica, necesita hacer un análisis profundo o utilizar una biblioteca de precisión arbitraria o matemática exacta que pueda manejar sus números correctamente.