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

double round(double);

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

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

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


当前回答

如果您需要能够在支持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++ 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(),并使用它来创建你自己的头文件来定义函数(如果它还没有定义的话)。但是请注意,这可能不是最佳解决方案,特别是如果您需要为多个平台编译时。

值得注意的是,如果想要从舍入中得到整数结果,则不需要通过上下限或上下限。也就是说,

int round_int( double r ) {
    return (r > 0.0) ? (r + 0.5) : (r - 0.5); 
}

它在cmath中从c++ 11开始提供(根据http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2012/n3337.pdf)

#include <cmath>
#include <iostream>

int main(int argc, char** argv) {
  std::cout << "round(0.5):\t" << round(0.5) << std::endl;
  std::cout << "round(-0.5):\t" << round(-0.5) << std::endl;
  std::cout << "round(1.4):\t" << round(1.4) << std::endl;
  std::cout << "round(-1.4):\t" << round(-1.4) << std::endl;
  std::cout << "round(1.6):\t" << round(1.6) << std::endl;
  std::cout << "round(-1.6):\t" << round(-1.6) << std::endl;
  return 0;
}

输出:

round(0.5):  1
round(-0.5): -1
round(1.4):  1
round(-1.4): -1
round(1.6):  2
round(-1.6): -2

基于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);
    }

Boost中还实现了某种类型的舍入:

#include <iostream>

#include <boost/numeric/conversion/converter.hpp>

template<typename T, typename S> T round2(const S& x) {
  typedef boost::numeric::conversion_traits<T, S> Traits;
  typedef boost::numeric::def_overflow_handler OverflowHandler;
  typedef boost::numeric::RoundEven<typename Traits::source_type> Rounder;
  typedef boost::numeric::converter<T, S, Traits, OverflowHandler, Rounder> Converter;
  return Converter::convert(x);
}

int main() {
  std::cout << round2<int, double>(0.1) << ' ' << round2<int, double>(-0.1) << ' ' << round2<int, double>(-0.9) << std::endl;
}

注意,这仅在执行到整数的转换时有效。