Стандарт C ++ 03 опирается на стандарт C90 для того, что стандарт называет Стандарт C Library , который описан в проекте стандарта C ++ 03 (, ближайший к общедоступному доступу). черновой вариант стандарта C ++ 03 - N1804 ) раздел 1.2
нормативные ссылки :
Библиотека, описанная в пункте 7 ИСО / МЭК 9899: 1990 и в пункте 7
ISO / IEC 9899 / Amd.1: 1995 в дальнейшем называется стандартом C
Библиотека. 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 который:
Вычисляет ближайшее целое число, не большее по величине, чем аргумент.
#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 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 потенциально может быть вариантом, поскольку это хорошо протестированная реализация.