Подтвердить что ты не робот

Выполняет ли литье в int после std:: floor гарантированный правильный результат?

Мне нужна функция floor с синтаксисом

int floor(double x);

но std::floor возвращает a double. Является

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

гарантированно даст мне правильное целое число, или я могу решить проблему отдельно? Кажется, это работает, но я хотел бы точно знать.

Для бонусных очков, почему черт std::floor возвращает a double в первую очередь?

4b9b3361

Ответ 1

Диапазон double больше, чем диапазон 32 или 64 битных целых чисел, поэтому std::floor возвращает double. Кастинг в int должен быть точным до тех пор, пока он находится в соответствующем диапазоне, но имейте в виду, что double не может точно представлять все 64-битные целые числа, поэтому вы также можете столкнуться с ошибками, когда вы выходите за пределы точки точность которого double такова, что разность между двумя последовательными удвоениями больше 1.

Ответ 2

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

делает в значительной степени то, что вы хотите, да. Он дает вам ближайшее целое число, округленное к -infinity. По крайней мере, пока ваш вход находится в диапазоне, представляемом ints. Я не уверен, что вы подразумеваете под "добавлением .5 и еще чего-то, но он не будет иметь такого же эффекта

И std:: floor возвращает double, потому что это самый общий. Иногда вам может понадобиться округлить float или double, но сохранить тип. То есть, от 1.3f до 1.0f, а не до 1.

Это было бы трудно сделать, если std:: floor возвратил int. (или, по крайней мере, у вас будет лишний ненужный бросок, замедляющий работу).

Если пол выполняет только округление, не изменяя тип, вы можете применить его к int, если вам нужно.

Другая причина заключается в том, что диапазон удвоений намного больше, чем у ints. Возможно, не удастся обойти все двойники до целых чисел.

Ответ 3

В стандарте С++ говорится (4.9.1):

"rvalue типа с плавающей точкой может быть преобразовано в rvalue целочисленного типа. Преобразование обрезается, то есть дробная часть отбрасывается. Поведение undefined, если усеченное значение не может быть представлено в тип назначения".

Итак, если вы конвертируете double в int, число находится в пределах интервала int, а требуемое округление - к нулю, тогда достаточно просто указать число в int:

(целое) х;

Ответ 4

Если вы хотите иметь дело с различными числовыми условиями и хотите обрабатывать различные типы конверсий контролируемым образом, то, возможно, вам стоит взглянуть на Boost.NumericConversion. Эта библиотека позволяет обрабатывать странные случаи (например, вне диапазона, округление, диапазоны и т.д.).

Вот пример из документации:

#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;
}

Ответ 5

Большая часть стандартной математической библиотеки использует удвоение, но также предоставляет версии с плавающей точкой. std:: floorf() - это единственная версия версии std:: floor(), если вы предпочитаете не использовать удвоения.

Изменить: я удалил часть своего предыдущего ответа. Я сказал, что пол был излишним при бросании в int, но я забыл, что это верно только для положительных чисел с плавающей точкой.