我需要一个简单的浮点舍入函数,这样:

double round(double);

round(0.1) = 0
round(-0.1) = 0
round(-0.9) = -1

我可以在math.h中找到ceil()和floor() -但没有round()。

它是否以另一个名字出现在标准c++库中,或者它是否丢失了??


当前回答

这里有两个问题:

舍入转换 类型转换。

四舍五入转换意味着四舍五入±浮动/双到最近的地板/天花板浮动/双。 也许你的问题到此为止了。 但如果希望返回Int/Long类型,则需要执行类型转换,因此“溢出”问题可能会影响您的解决方案。所以,检查一下函数中的错误

long round(double x) {
   assert(x >= LONG_MIN-0.5);
   assert(x <= LONG_MAX+0.5);
   if (x >= 0)
      return (long) (x+0.5);
   return (long) (x-0.5);
}

#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
      error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

来源:http://www.cs.tut.fi/~jkorpela/round.html

其他回答

基于Kalaxy的响应,下面是一个模板化的解决方案,它将任何浮点数舍入为基于自然舍入的最接近的整数类型。如果值超出了整数类型的范围,它还会在调试模式下抛出一个错误,从而大致作为一个可行的库函数。

    // round a floating point number to the nearest integer
    template <typename Arg>
    int Round(Arg arg)
    {
#ifndef NDEBUG
        // check that the argument can be rounded given the return type:
        if (
            (Arg)std::numeric_limits<int>::max() < arg + (Arg) 0.5) ||
            (Arg)std::numeric_limits<int>::lowest() > arg - (Arg) 0.5)
            )
        {
            throw std::overflow_error("out of bounds");
        }
#endif

        return (arg > (Arg) 0.0) ? (int)(r + (Arg) 0.5) : (int)(r - (Arg) 0.5);
    }

这里有两个问题:

舍入转换 类型转换。

四舍五入转换意味着四舍五入±浮动/双到最近的地板/天花板浮动/双。 也许你的问题到此为止了。 但如果希望返回Int/Long类型,则需要执行类型转换,因此“溢出”问题可能会影响您的解决方案。所以,检查一下函数中的错误

long round(double x) {
   assert(x >= LONG_MIN-0.5);
   assert(x <= LONG_MAX+0.5);
   if (x >= 0)
      return (long) (x+0.5);
   return (long) (x-0.5);
}

#define round(x) ((x) < LONG_MIN-0.5 || (x) > LONG_MAX+0.5 ?\
      error() : ((x)>=0?(long)((x)+0.5):(long)((x)-0.5))

来源:http://www.cs.tut.fi/~jkorpela/round.html

如果您需要能够在支持c++ 11标准的环境中编译代码,但也需要能够在不支持c++ 11标准的环境中编译相同的代码,那么您可以使用函数宏在std::round()和每个系统的自定义函数之间进行选择。只需将-DCPP11或/DCPP11传递给兼容c++ 11的编译器(或使用其内置的版本宏),并创建一个像这样的头文件:

// File: rounding.h
#include <cmath>

#ifdef CPP11
    #define ROUND(x) std::round(x)
#else    /* CPP11 */
    inline double myRound(double x) {
        return (x >= 0.0 ? std::floor(x + 0.5) : std::ceil(x - 0.5));
    }

    #define ROUND(x) myRound(x)
#endif   /* CPP11 */

有关快速示例,请参见http://ideone.com/zal709。

这在不兼容c++ 11的环境中近似于std::round(),包括保留-0.0的符号位。然而,这可能会导致轻微的性能损失,并且在舍入某些已知的“问题”浮点值(如0.4999999999999999994或类似值)时可能会出现问题。

或者,如果你有c++ 11兼容的编译器,你可以从它的<cmath>头文件中获取std::round(),并使用它来创建你自己的头文件来定义函数(如果它还没有定义的话)。但是请注意,这可能不是最佳解决方案,特别是如果您需要为多个平台编译时。

c++ 03标准依赖于C90标准,该标准称为标准C库,该标准在c++ 03标准草案中涵盖(最接近c++ 03的公开标准草案是N1804) 1.2节规范参考:

ISO/IEC 9899:1990第7条和ISO/IEC 9899:1990第7条描述的库 ISO / IEC 9899 / Amd。1:1995以下称为标准C Library.1)

如果我们去cppreference上的round, lround, llround的C文档,我们可以看到round和相关函数是C99的一部分,因此在c++ 03或更早的版本中不可用。

在c++ 11中,这种情况发生了变化,因为c++ 11依赖于C标准库的C99草案标准,因此提供了std::round和for整型返回类型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应用程序,你最好使用boost round, round, lround, llround或boost trunc。

滚出自己版本的圆很难

滚动你自己的可能不值得努力,因为它比看起来更难:四舍五入浮点到最近的整数,第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 ) 

会造成溢出,(看现场)。

通过在C中实现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可能是一个选择,因为它是一个经过良好测试的实现。

你可以四舍五入到n位精度:

double round( double x )
{
const double sd = 1000; //for accuracy to 3 decimal places
return int(x*sd + (x<0? -0.5 : 0.5))/sd;
}