Стандарт C ++ 03 опирается на стандарт C90 для того, что стандарт называет стандартной библиотекой C, которая описана в разделе проекта стандарта C ++ 03 ( ближайший общедоступный проект стандарта C ++ 03 - N1804 ). 1.2
Нормативные ссылки :
Библиотека, описанная в п. 7 ИСО / МЭК 9899: 1990 и п. 7 ИСО / МЭК 9899 / Amd.1: 1995, в дальнейшем называется стандартной библиотекой С. 1)
Если мы перейдем к документации C для round, lround, llround по cppreference, мы увидим, что round и связанные функции являются частью C99 и, следовательно, не будут доступны в C ++ 03 или более ранних версиях.
В C ++ 11 это меняется, поскольку C ++ 11 использует черновой стандарт C99 для стандартной библиотеки C и, следовательно, предоставляет std :: round и для целочисленных возвращаемых типов std :: lround, std :: llround :
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::round( 0.4 ) << " " << std::lround( 0.4 ) << " " << std::llround( 0.4 ) << std::endl ;
std::cout << std::round( 0.5 ) << " " << std::lround( 0.5 ) << " " << std::llround( 0.5 ) << std::endl ;
std::cout << std::round( 0.6 ) << " " << std::lround( 0.6 ) << " " << std::llround( 0.6 ) << std::endl ;
}
Другой вариант также из C99 будет std :: trunc, который:
Вычисляет ближайшее целое число, не большее по величине, чем arg.
#include <iostream>
#include <cmath>
int main()
{
std::cout << std::trunc( 0.4 ) << std::endl ;
std::cout << std::trunc( 0.9 ) << std::endl ;
std::cout << std::trunc( 1.1 ) << std::endl ;
}
Если вам необходимо поддерживать приложения, не относящиеся к C ++ 11, лучше всего использовать усиление раунда, округления, округления, округления или усиления .
Раскатать свою версию раунда сложно
Свернуть свое собственное, вероятно, не стоит таких усилий, как сложнее, чем кажется: округление числа с плавающей точкой до ближайшего целого числа, часть 1 , округление числа с плавающей точкой до ближайшего целого числа, часть 2 и округление числа с плавающей точкой до ближайшего целого числа, часть 3 объясняют:
Например, общий ролл, в котором ваша реализация использует std::floor
и добавляет 0.5
, не работает для всех входов
double myround(double d)
{
return std::floor(d + 0.5);
}
Один вход, для которого это не удастся 0.49999999999999994
, ( посмотреть его вживую ).
Другая распространенная реализация включает приведение типа с плавающей запятой к интегральному типу, который может вызывать неопределенное поведение в случае, когда интегральная часть не может быть представлена в типе назначения. Мы можем видеть это из черновика стандартного раздела C ++ 4.9
преобразования с плавающей запятой, который гласит ( выделение мое ):
Значение типа с плавающей запятой может быть преобразовано в значение типа целого числа. Преобразование усекается; то есть дробная часть отбрасывается. Поведение не определено, если усеченное значение не может быть представлено в типе назначения. [...]
Например:
float myround(float f)
{
return static_cast<float>( static_cast<unsigned int>( f ) ) ;
}
Учитывая std::numeric_limits<unsigned int>::max()
это , 4294967295
то следующий вызов:
myround( 4294967296.5f )
вызовет переполнение, ( смотрите его вживую ).
Мы можем увидеть, насколько это действительно сложно, посмотрев на этот ответ в Кратком способе реализации round () в C? которая ссылается на версию newlibs одинарной точности float round. Это очень длинная функция для чего-то, что кажется простым. Представляется маловероятным, чтобы кто-либо, не имеющий глубоких знаний о реализации с плавающей запятой, мог правильно реализовать эту функцию:
float roundf(x)
{
int signbit;
__uint32_t w;
/* Most significant word, least significant word. */
int exponent_less_127;
GET_FLOAT_WORD(w, x);
/* Extract sign bit. */
signbit = w & 0x80000000;
/* Extract exponent field. */
exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
if (exponent_less_127 < 23)
{
if (exponent_less_127 < 0)
{
w &= 0x80000000;
if (exponent_less_127 == -1)
/* Result is +1.0 or -1.0. */
w |= ((__uint32_t)127 << 23);
}
else
{
unsigned int exponent_mask = 0x007fffff >> exponent_less_127;
if ((w & exponent_mask) == 0)
/* x has an integral value. */
return x;
w += 0x00400000 >> exponent_less_127;
w &= ~exponent_mask;
}
}
else
{
if (exponent_less_127 == 128)
/* x is NaN or infinite. */
return x + x;
else
return x;
}
SET_FLOAT_WORD(x, w);
return x;
}
С другой стороны, если ни одно из других решений не является пригодным для использования, newlib потенциально может быть вариантом, поскольку это хорошо проверенная реализация.
std::cout << std::fixed << std::setprecision(0) << -0.9
, например.