round()用于C ++中的float

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

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

我可以在math.h中findceil()floor() ,但不是round()

它以另一个名字出现在标准的C ++库中,还是缺less?

C ++ 98标准库中没有round()。 你可以自己写一个。 以下是半舍弃的实施:

 double round(double d) { return floor(d + 0.5); } 

在C ++ 98标准库中没有循环函数的可能原因是它实际上可以以不同的方式实现。 以上是一个常用的方法,但也有其他的一些例子,比如说,如果你打算进行大量的四舍五入,那么这种方式就不那么有偏见了。 尽pipe如此,实施起来还是比较复杂的。

Boost提供了一组简单的舍入函数。

 #include <boost/math/special_functions/round.hpp> double a = boost::math::round(1.5); // Yields 2.0 int b = boost::math::iround(1.5); // Yields 2 as an integer 

有关更多信息,请参阅Boost文档 。

编辑 :自C ++ 11以来,有std::roundstd::lroundstd::llround

值得注意的是,如果你想要舍入的整数结果,你不需要通过ceil或floor来传递它。 也就是说,

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

C ++ 03标准依赖于C90标准,该标准称为C ++ 03标准草案(C ++ 03 最接近的公开可用草案标准是N1804 )所涵盖的标准C库 1.2 规范性参考

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

如果我们转到C语言环境的文档,那么我们可以看到, round和相关函数是C99的一部分,因此在C ++ 03或以前版本中将不可用。

在C ++ 11中,由于C ++ 11依赖于C标准库的C99草案标准,因此提供了std :: round和整型返回typesstd :: 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循环,iround,lround,llround或boost trunc 。

滚动你自己的版本很难

滚动你自己可能是不值得的努力,因为哈德比看起来:舍入浮点数最接近的整数,第1部分 , 舍入浮点数最接近的整数,第2部分和舍入浮点数最接近的整数,第3部分解释:

例如,一个普通的使用std::floor实现的实现,并且添加0.5不适用于所有的input:

 double myround(double d) { return std::floor(d + 0.5); } 

一个input失败的是0.49999999999999994 ,( 看它现场 )。

另一个常见的实现涉及将浮点types转换为整型,在整型部分不能在目标types中表示的情况下,可以调用未定义的行为。 我们可以从C ++标准草案4.9 浮动积分转换我的重点 )中看到这一点:

浮点types的前值可以转换为整数types的前值。 转换截断; 即小数部分被丢弃。 如果截断的值不能在目标types中表示,则行为未定义。 […]

例如:

 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()吗? 它引用了newlibs版本的单精度浮轮。 对于看似简单的东西来说,这是一个很长的function。 任何不熟悉浮点实现的人都不可能正确地实现这个function:

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

另一方面,如果没有其他的解决scheme是可用的, newlib可能是一个select,因为它是一个经过很好testing的实现。

从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 

通常实现为floor(value + 0.5)

编辑:它可能不是所谓的四舍五入,因为至less有三个舍入algorithm我知道:舍入零,舍入到最接近的整数,银行家的四舍五入。 你正在问到最接近的整数。

有两个问题我们正在看:

  1. 舍入转换
  2. types转换。

舍入转换意味着舍入±浮动/双倍到最近的楼层/细胞浮动/双重。 可能是你的问题在这里结束。 但是,如果您希望返回Int / Long,则需要执行types转换,因此“溢出”问题可能会影响您的解决scheme。 所以,请检查你的function错误

 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

在Boost中也实现了某种types的舍入:

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

请注意,这仅适用于进行整数转换的情况。

您可以使用以下数字精确到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; } 

如果你最终想把你的round()函数的double输出转换为一个int ,那么这个问题的接受的解决scheme将如下所示:

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

在统一随机值的情况下,这个时钟在我的机器上大约为8.88ns

就我所知,下面的function是相同的,但是在我的机器上,在2.48ns的时钟,为了显着的性能优势:

 int roundint (double r) { int tmp = static_cast<int> (r); tmp += (r-tmp>=.5) - (r-tmp<=-.5); return tmp; } 

其中更好的性能的原因是跳过分支。

当心楼层(x + 0.5),这里是在范围[2 ^ 52,2 ^ 53]中奇数可能发生的情况:

 -bash-3.2$ cat >test-round.c <<END #include <math.h> #include <stdio.h> int main() { double x=5000000000000001.0; double y=round(x); double z=floor(x+0.5); printf(" x =%f\n",x); printf("round(x) =%f\n",y); printf("floor(x+0.5)=%f\n",z); return 0; } END -bash-3.2$ gcc test-round.c -bash-3.2$ ./a.out x =5000000000000001.000000 round(x) =5000000000000001.000000 floor(x+0.5)=5000000000000002.000000 

这是http://bugs.squeak.org/view.php?id=7134使用类似@konik之一的解决scheme

编辑:我自己的健壮的版本将是类似的东西

 double round(double x) { double truncated,roundedFraction; double fraction= modf(x, &truncated); modf(2.0*fraction, &roundedFraction); return truncated + roundedFraction; } 

编辑2: 这里给出了另一个避免楼层(x + 0.5)的原因

没有必要实现任何东西,所以我不知道为什么如此多的答案涉及定义,函数或方法。

在C99

对于typesgenericsmacros,我们有以下头文件和头文件<tgmath.h>。

 #include <math.h> double round (double x); float roundf (float x); long double roundl (long double x); 

如果你不能编译这个,你可能会遗漏math库。 一个类似于这个的命令适用于我有的每个C编译器(几个)。

 gcc -lm -std=c99 ... 

在C ++ 11中

在#include <cmath>中,我们在依赖于IEEE双精度浮点的地方有以下额外的重载。

 #include <math.h> double round (double x); float round (float x); long double round (long double x); double round (T x); 

标准命名空间也有等价物 。

如果你不能编译这个,你可能会使用C编译而不是C ++。 下面的基本命令不会产生错误和警告,使用g ++ 6.3.1,x86_64-w64-mingw32-g ++ 6.3.0,clang-x86_64 ++ 3.8.0和Visual C ++ 2015 Community。

 g++ -std=c++11 -Wall 

与序数部门

当将两个序数分开时,其中T是短的,int,long或者其他序数,舍入expression式就是这个。

 T roundedQuotient = (2 * integerNumerator + 1) / (2 * integerDenominator); 

准确性

毫无疑问,在浮点运算中会出现奇怪的错误,但这只是在数字出现的时候,而与舍入无关。

来源不仅仅是IEEE表示浮点数的尾数中的有效位数,它与我们的小数思想有关。

十是五和二的乘积,五和二是相对的。 因此,对于所有二进制数字表示,IEEE浮点标准不可能完美地表示为十进制数。

这不是舍入algorithm的问题。 在selecttypes和计算devise,数据input和数字显示时应该考虑math现实。 如果应用程序显示显示这些十进制二进制转换问题的数字,则该应用程序在视觉上expression数字现实中不存在的准确性,应该进行更改。

函数双轮(双)使用modf函数。

 double round(double x) { using namespace std; if ((numeric_limits<double>::max() - 0.5) <= x) return numeric_limits<double>::max(); if ((-1*std::numeric_limits<double>::max() + 0.5) > x) return (-1*std::numeric_limits<double>::max()); double intpart; double fractpart = modf(x, &intpart); if (fractpart >= 0.5) return (intpart + 1); else if (fractpart >= -0.5) return intpart; else return (intpart - 1) ; } 

要编译干净,包含“math.h”和“limits”是必要的。 该函数按照以下舍入模式工作:

  • 5.0的一轮是5.0
  • 3.8的一轮是4.0
  • 2.3是2.0
  • 1.5是2.0
  • 0.501是1.0
  • 0.5的一轮是1.0
  • 0.499是0.0
  • 0.01的圆是0.0
  • 0.0的一轮是0.0
  • -0.01是-0.0
  • -0.499的一轮是-0.0
  • -0.5的一轮是-0.0
  • -0.501是-1.0
  • -1.5的-1是-1.0
  • -2.3的一轮是-2.0
  • -3.8是-4.0
  • -5.0是-5.0

如果您需要能够在支持C ++ 11标准的环境中编译代码,而且需要能够在不支持它的环境中编译相同的代码,则可以使用函数macros在std :: round()和每个系统的自定义函数。 只要将-DCPP11/DCPP11给符合C ++ 11的编译器(或使用其内置的版本macros),并制作如下所示的标头:

 // 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.49999999999999994或相似值)四舍五入的问题。

或者,如果您有权访问C ++ 11兼容的编译器,则可以从其<cmath>头中获取std :: round(),并使用它创build自己的头,如果该头尚未定义。 请注意,这可能不是一个最佳解决scheme,但是,特别是如果您需要编译多个平台。

基于Kalaxy的回应,以下是一个模板化的解决scheme,根据自然舍入将任意浮点数舍入为最接近的整数types。 如果该值超出了整数types的范围,它也会在debugging模式下引发错误,从而大致成为可行的库函数。

  // 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); } 

我做到了这一点:

 #include <math.h> #define round(x) ((x < 0) ? (ceil((x)-0.5)) : (floor((x)+0.5))) 

这似乎是工作。

我在asm for x86体系结构和MS VS特定的C ++中使用下面的round的实现:

 __forceinline int Round(const double v) { int r; __asm { FLD v FISTP r FWAIT }; return r; } 

UPD:返回double值

 __forceinline double dround(const double v) { double r; __asm { FLD v FRNDINT FSTP r FWAIT }; return r; } 

输出:

 dround(0.1): 0.000000000000000 dround(-0.1): -0.000000000000000 dround(0.9): 1.000000000000000 dround(-0.9): -1.000000000000000 dround(1.1): 1.000000000000000 dround(-1.1): -1.000000000000000 dround(0.49999999999999994): 0.000000000000000 dround(-0.49999999999999994): -0.000000000000000 dround(0.5): 0.000000000000000 dround(-0.5): -0.000000000000000 

处理负值的另一个解决scheme是:

 #include <iostream> #include <math.h> double round(double a) { return floor(a + (0.5*a/a));//to extract sign - a/a } int main() { std::cout << round(0.1) << std::endl; // 0 std::cout << round(-0.1) << std::endl; // 0 std::cout << round(0.9) << std::endl; // 1 std::cout << round(-0.9) << std::endl; //-1 std::cout << round(0.5) << std::endl; // 1 std::cout << round(-0.5) << std::endl; // 0 std::cout << round(0.4999) << std::endl; // 0 std::cout << round(-0.4999) << std::endl; // 0 std::cout << round(0.50001) << std::endl; // 1 std::cout << round(-0.50001) << std::endl;//-1 return 0; } 
 //convert the float to a string //might use stringstream but it looks like it truncates the float to only //5 decimal points (maybe thats what u want anyway =P) float MyFloat = 5.11133333311111333; float NewConvertedFloat = 0.0; string FirstString = " "; string SecondString = " "; stringstream ss (stringstream::in | stringstream::out); ss << MyFloat; FirstString = ss.str(); //take out how ever many decimal places you want //(this is a string it includes the point) SecondString = FirstString.substr(0,5); //whatever precision decimal place you want //convert it back to a float stringstream(SecondString) >> NewConvertedFloat; cout << NewConvertedFloat; system("pause"); 

这可能是一个不合理的肮脏的转换方式,但是,它工作大声笑。 它的好处是因为它适用于实际的浮动。 不只是直观地影响输出。

我做了什么

 #include <cmath.h> using namespace std; double roundh(double number,int place){ /*place = decimal point. putting in 0 will make it round to whole number. putting in 1 will round to the tenths digit.*/ number *= 10^place; int istack = (int)floor(number); int out = number-istack; if (out < 0.5){ floor(number); number /= 10^place; return number; } if (out > 0.4) { ceil(number); number /= 10^place; return number; } } 

被接受的答案是错误的。

例如,round(-3.7)= -4,但它会给你-3而不是-4。

这样做(假设x是双倍):

 #include "math.h" double n = floor( x + 0.5 ); 

要么

 int n = (int)floor( x + 0.5 ); 

如果你想演员,因为你是一个数字。