español c++ math floor

c++ - español - ¿Fundir a int int after std:: floor garantiza el resultado correcto?



ceil c++ español (5)

Me gustaría una función de floor con la sintaxis

int floor(double x);

pero std::floor devuelve un double . Es

static_cast <int> (std::floor(x));

garantizado para darme el entero correcto, o podría tener un problema de uno a uno? Parece que funciona, pero me gustaría saberlo con certeza.

Para puntos de bonificación, ¿por qué demonios std::floor devuelve un double en primer lugar?


El estándar de C ++ dice (4.9.1):

"Un valor en r de un tipo de punto flotante se puede convertir en un valor r de un tipo entero. La conversión se trunca, es decir, la parte fraccional se descarta. El comportamiento no está definido si el valor truncado no se puede representar en el tipo de destino".

Entonces, si está convirtiendo un doble en un int, el número está dentro del rango de int y el redondeo requerido es hacia cero, entonces es suficiente simplemente para convertir el número a int:

(int) x;


El rango de doble es mucho mayor que el rango de enteros de 32 o 64 bits, por lo que std::floor devuelve un double . Casting to int debería estar bien siempre que esté dentro del rango apropiado, pero ten en cuenta que un double no puede representar todos los enteros de 64 bits exactamente, por lo que también puedes terminar con errores cuando vas más allá del punto en el que la precisión de double es tal que la diferencia entre dos dobles consecutivos es mayor que 1.


La mayor parte de la biblioteca matemática estándar usa dobles pero también ofrece versiones flotantes. std :: floorf () es la única versión de precisión de std :: floor () si prefiere no usar dobles.

Editar: eliminé parte de mi respuesta anterior. Yo había declarado que el piso era redundante cuando lancé a int, pero olvidé que esto solo es cierto para los números positivos de coma flotante.


Si desea tratar varias condiciones numéricas y desea manejar diferentes tipos de conversiones de forma controlada, entonces tal vez debería consultar Boost.NumericConversion . Esta biblioteca permite manejar casos extraños (como fuera de rango, redondeo, rangos, etc.)

Aquí está el ejemplo de la documentación:

#include <cassert> #include <boost/numeric/conversion/converter.hpp> int main() { typedef boost::numeric::converter<int,double> Double2Int ; int x = Double2Int::convert(2.0); assert ( x == 2 ); int y = Double2Int()(3.14); // As a function object. assert ( y == 3 ) ; // The default rounding is trunc. try { double m = boost::numeric::bounds<double>::highest(); int z = Double2Int::convert(m); // By default throws positive_overflow() } catch ( boost::numeric::positive_overflow const& ) { } return 0; }


static_cast <int> (std::floor(x));

hace más o menos lo que quieres, sí. Te da el entero más cercano, redondeado hacia -infinito. Al menos, siempre y cuando su entrada esté en el rango representable por ints. No estoy seguro de lo que quiere decir con ''agregar .5 y otras cosas, pero no tendrá el mismo efecto

Y std :: floor devuelve un doble porque es el más general. A veces es posible que desee redondear un flotante o doble, pero conservar el tipo. Es decir, alrededor de 1.3f a 1.0f, en lugar de a 1.

Eso sería difícil de hacer si std :: floor devolviera un int. (o al menos tendrías un elenco adicional innecesario allí desacelerando las cosas).

Si floor solo realiza el redondeo en sí mismo, sin cambiar el tipo, puedes convertirlo a int si / cuando lo necesites.

Otra razón es que el rango de dobles es mucho mayor que el de los ints. Puede que no sea posible redondear todos los dobles a ints.