Cast to int vs floor

120

¿Hay alguna diferencia entre estos:

float foo1 = (int)(bar / 3.0);
float foo2 = floor(bar / 3.0);

Según tengo entendido, ambos casos tienen el mismo resultado. ¿Hay alguna diferencia en el código compilado?

OgreSwamp
fuente
1
un poco mejor con floor, pero ten en cuenta que esto doubleno es para float. C99 también tiene floorfpara float.
Jens Gustedt
2
Entonces tienen el mismo resultado siempre que la barra sea positiva
Zac
1
(nota: en C ++ por favor #include<cmath>y use std::floor)
user202729
¿Qué tipo es bar?
chux - Reincorporar a Monica
@chux No importa, dividir por 3.0 lo convertirá en el doble de todos modos
kaalus

Respuestas:

193

La conversión a un int se truncará hacia cero. floor()se truncará hacia el infinito negativo. Esto le dará valores diferentes si barfueran negativos.

James Curran
fuente
15
Creo que has dado en el clavo aquí. Otra diferencia, si floor()es la intención, es si el valor de bares demasiado grande para caber en un int.
Fred Larson
¿Tiene alguna fuente para esa declaración?
Hola
1
Incluso cuando el resultado es positivo, no está garantizado. Vea esto y esto .
user202729
27

Como se dijo antes, para los números positivos son iguales, pero difieren para los números negativos. La regla es que int se redondea hacia 0, mientras que floor se redondea hacia infinito negativo.

floor(4.5) = (int)4.5 = 4
floor(-4.5) = -5 
(int)(-4.5) = -4

Dicho esto, también hay una diferencia en el tiempo de ejecución. En mi sistema, he cronometrado que el lanzamiento es al menos 3 veces más rápido que el piso.

Tengo un código que necesita la operación de piso de un rango limitado de valores, incluidos los números negativos. Y debe ser muy eficiente, por lo que usamos la siguiente función para ello:

int int_floor(double x) 
{ 
    return (int)(x+100000) - 100000; 
}

Por supuesto, esto fallará para valores muy grandes de x (se encontrará con algunos problemas de desbordamiento) y para valores negativos por debajo de -100000, etc. Pero lo he cronometrado para que sea al menos 3 veces más rápido que el piso, lo cual fue realmente crítico para nuestra aplicación. Tómelo con un grano de sal, pruébelo en su sistema, etc. pero vale la pena considerarlo en mi humilde opinión.

brice rebsamen
fuente
"Lo he cronometrado para que sea al menos 3 veces más rápido que el piso" -> OP está usando float, no double- tal vez doublefue su aplicación. Si está en C, asegúrese de usar floorf()con floats.
chux - Reincorporación a Monica
@chux Creo que la única razón por la que hay alguna diferencia es que el elenco permite una optimización en tiempo de compilación. Por lo tanto, es posible que la conversión se haya eliminado por completo durante la ejecución.
ClydeTheGhost
9

SO 101, no cambie su pregunta después de que las personas hayan respondido a su pregunta, en su lugar, escriba una nueva pregunta.

¿Por qué cree que tendrán el mismo resultado?

float foo = (int)(bar / 3.0) //will create an integer then assign it to a float

float foo = fabs(bar / 3.0 ) //will do the absolute value of a float division

bar = 1.0

foo1 = 0;
foo2 = 0.33333...
AndersK
fuente
1
¿Qué quieres decir con fabs? La pregunta era sobre floor. El piso de 0.33333... es 0.
Aaron Franke
2
@AaronFranke, la pregunta original ha sido modificada. Parece que pueden pasar muchas cosas en 8 años ;-) observe que otras respuestas tienen la misma premisa
AndersK
4

EDITAR: Porque la pregunta puede haber sido modificada debido a la confusión entre fabs()yfloor() .

Dadas las líneas de ejemplo de la pregunta original:

1.  float foo = (int)(bar / 3.0);

2.  float foo = fabs(bar / 3.0);

La diferencia es que si la barra es negativa el resultado será negativo con la primera pero positivo con la segunda. El primero se truncará a un número entero y el segundo devolverá el valor decimal completo, incluida la parte fraccionaria.

Amardeep AC9MF
fuente
3

Si. fabsdevuelve el valor absoluto de su argumento y la conversión a int provoca el truncamiento de la división (hasta el int más cercano), por lo que los resultados casi siempre serán diferentes.

warrenm
fuente
2

Hay dos diferencias principales:

  1. Como han señalado otros, la conversión a un número entero se truncará hacia cero, mientras floor()que siempre se truncará hacia el infinito negativo; este es un comportamiento diferente para un operando negativo.

  2. Nadie (todavía) parece haber señalado otra diferencia: si su argumento es mayor o igual a MAX_INT+1(o menor que -MAX_INT-1), la conversión a an intresultará en la eliminación de los bits superiores (C, probablemente) o un comportamiento indefinido ( C ++ y posiblemente C). Por ejemplo, si su intes de 32 bits, solo tendrá un bit de signo más 31 bits de datos. Entonces, usar esto con un doubletamaño grande producirá resultados no deseados.

abligh
fuente
2.a. La condición exacta para la conversión a intdesbordamiento es que el argumento sea mayor o igual a INT_MAX+1. Simétricamente, la condición para el subdesbordamiento es que el argumento sea menor o igual a INT_MIN-1.
Pascal Cuoq
1
2.b. El desbordamiento en la conversión de punto flotante a entero es un comportamiento indefinido en C ++. No “da como resultado la eliminación de los bits más altos”. Ver (aunque está escrito para C): blog.frama-c.com/index.php?post/2013/10/09/…
Pascal Cuoq
0

(int) xes una solicitud para mantener la parte entera de x(no hay redondeo aquí)

fabs(x)= | x | para que sea>= 0 ;

Ej: (int) -3.5devoluciones -3; fabs(-3.5)devoluciones 3.5;

En general, fabs (x) >= xpara todo x;

x >= (int) x Si x >= 0

x < (int) x Si x < 0

Paul Hoang
fuente
x = -3 fabs (-3) = 3 (int) -3 = -3; Creo que las últimas desigualdades se mantienen. ¿Puede explicar más por qué está mal?
Paul Hoang
Lo siento, quise decir -3.5, el ejemplo que diste. -3> -3.5
Dennis Zickefoose
3
La última declaración debería ser "x <= int (x) si x <0", y no "x <(int) x si x <0": los enteros negativos permanecen igual.
Tomasz Gandor