C ++에서 float의 round ()


232

간단한 부동 소수점 반올림 함수가 필요합니다.

double round(double);

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

내가 찾을 수 ceil()floor()math.h에 -하지만round() .

표준 C ++ 라이브러리에 다른 이름으로 존재합니까, 아니면 없습니까?


1
숫자를 반올림 된 숫자로 출력하려면 std::cout << std::fixed << std::setprecision(0) << -0.9예를 들어 할 수있는 것처럼 보입니다 .
Frank

44
이것을 보호하는 중 ... 새로운 반올림 체계를 가진 새로운 사용자는 먼저 기존 답변을 읽어야합니다.
Shog9

12
round에서 C ++ 11부터 사용할 수 있습니다 <cmath>. 불행히도 Microsoft Visual Studio를 사용하는 경우 여전히 누락되었습니다. connect.microsoft.com/VisualStudio/feedback/details/775474/…
Alessandro Jacopson

3
내 대답에서 알 수 있듯이 자신 round을 굴리는 것은 많은주의 사항이 있습니다. C ++ 11 이전에는 표준이 포함되지 않은 C90에 의존했습니다 round. C ++ 11은 C99에 의존 round하지만 trunc다른 속성을 가지고 있으며 응용 프로그램에 따라 더 적합 할 수있는 것을 포함합니다. 또한 대부분의 답변은 사용자가 더 많은 문제가있는 정수 유형을 반환하기를 원할 수도 있습니다.
Shafik Yaghmour

2
@uvts_cvs이, 비주얼 스튜디오의 최신 버전에 문제가 될 것 같지 않습니다 이 살고 참조 .
Shafik Yaghmour

답변:


144

C ++ 98 표준 라이브러리에는 round ()가 없습니다. 그래도 직접 쓸 수 있습니다. 다음은 반감기 구현입니다 .

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

C ++ 98 표준 라이브러리에 라운드 함수가없는 가능한 이유는 실제로 다른 방식으로 구현 될 수 있기 때문입니다. 위의 한 가지 일반적인 방법이지만 round-to-even 과 같은 다른 방법이 있습니다. 편향이 적고 많은 라운딩을 할 경우 일반적으로 더 좋습니다. 그래도 구현하기가 조금 더 복잡합니다.


53
음수를 올바르게 처리하지 못합니다. litb의 답변이 맞습니다.
등록 된 사용자

39
@InnerJoin : 예, litb의 답변과 다르게 음수를 처리하지만 "올바르지"않습니다.
Roddy 2016 년

39
잘라 내기 전에 0.5를 추가하면 0.49999999999999994를 포함한 여러 입력에 대해 가장 가까운 정수로 반올림되지 않습니다. 참조 : blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
Pascal Cuoq

10
@ Sergi0 : 중간 지점에서 발생하는 일을 결정하는 반올림에 대한 정의둘 이상 있기 때문에 "올바른"및 "올바르지 않은"은 없습니다 . 판단을 통과하기 전에 사실을 확인하십시오.
Jon

16
@ MuhammadAnnaqeeb : 당신이 맞아요, C ++ 11 출시 이후로 상황이 크게 향상되었습니다. 인생이 힘들고 기쁨이 적었던 다른 시간에이 질문을하고 답했습니다. 그것은 당시에 살아남아 싸운 영웅들과 여전히 현대적인 도구를 사용할 수없는 가난한 영혼들을위한 명예로 남아 있습니다.
Andreas Magnusson

96

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::round, std::lround하고std::llround .


2
나는 이미 내 프로젝트에서 부스트를 사용하고 있었으며, +1로 순진한 floor(value + 0.5)접근 방식을 사용하는 것보다 훨씬 낫습니다 !
Gustavo Maciel 2018 년

@GustavoMaciel 나는 게임에 약간 늦었다는 것을 알고 있지만 부스트 구현은 floor(value + 0.5)입니다.
n. '대명사'm.

실제로는 그렇지 않습니다 : github.com/boostorg/math/blob/develop/include/boost/math/… 4 년 후, 나는 floor(value + 0.5)그것이 순진하지 않고 오히려 문맥과 본성에 의존 한다고 말하고 싶습니다 반올림하려는 값
Gustavo Maciel

84

는 C ++ 03 표준에 대한 C90 표준에 의존하는 것을 표준 통화량 표준 C 라이브러리 초안 C ++ 03 표준에 덮여 ( C ++ 03 N1804에 가장 가까운 공개 초안 표준 섹션) 1.2 참조 규격 :

ISO / IEC 9899 : 1990의 7 절과 ISO / IEC 9899 / Amd.1 : 1995의 7 절에 설명 된 라이브러리를 이하 표준 C 라이브러리라고합니다. 1)

우리가에 가면 라운드, lround에 대한 C 문서, cppreference에 llround은 우리가 볼 수있는 및 관련 기능의 일부 C99 때문에 03 또는 이전 ++ C에서 사용할 수 없습니다.

C ++ 11에서는 C ++ 11이 C 표준 라이브러리 에 대한 C99 초안 표준을 사용 하므로 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 응용 프로그램을 지원 해야하는 경우 가장 좋은 방법은 boost round, iround, 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 부동 통합 변환 말한다 ( 강조 광산 .

부동 소수점 유형의 prvalue는 정수 유형의 prvalue로 변환 될 수 있습니다. 변환이 잘립니다. 즉, 분수 부분은 폐기됩니다. 잘린 값을 대상 유형으로 표시 할 수없는 경우 동작이 정의되지 않습니다. [...]

예를 들면 다음과 같습니다.

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 버전 을 참조 합니다. 단순 해 보이는 것으로 매우 긴 기능입니다. 부동 소수점 구현에 대한 친밀한 지식이없는 사람이라면 누구나이 함수를 올바르게 구현할 수 없을 것 같습니다.

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 은 테스트가 잘된 구현이므로 옵션이 될 수 있습니다.


5
@downvoter 개선 할 수있는 것을 설명해주세요. 여기에 나오는 대부분의 대답은 그들이 어떤 형태로든 실패하는 자신의 라운드를 굴 리려고 시도하기 때문에 잘못되었습니다. 설명에 빠진 것이 있으면 알려주세요.
Shafik Yaghmour

1
좋은 완전한 답변-특히 0.5 부분 미만입니다. 또 다른 틈새 : round(-0.0). C 사양이 지정되지 않은 것 같습니다. -0.0결과적으로 기대 합니다.
chux-복원 Monica Monica

3
@chux가 흥미롭고 IEEE 754-2008 표준은 반올림이 0 및 무한대의 부호를 유지하도록 지정합니다 (5.9 참조).
Ruslan

1
@ Shafik 이것은 훌륭한 답변입니다. 반올림조차 사소한 작업이라고 생각한 적이 없습니다.
Ruslan

1
아마도 C ++ 11을 숫자 및 성능상의 이유로 사용할 수있는 std::rint()경우보다 선호되는 std::round()경우가 있습니다. round()의 특수 모드 와 달리 현재 반올림 모드를 사용 합니다. rint단일 명령에 인라인 할 수 있는 x86에서 훨씬 더 효율적일 수 있습니다 . (gcc와 clang은 -ffast-math godbolt.org/g/5UsL2e 없이도 수행하지만 clang은 거의 동등한 것을 인라인합니다 nearbyint()) ARM은 단일 명령어를 지원 round()하지만 x86에서는 여러 명령어로만 인라인 할 수 있습니다-ffast-math
Peter Cordes

71

반올림에서 정수 결과를 원한다면 ceil 또는 floor를 통해 전달할 필요가 없습니다. 즉,

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

3
0.49999999999999994에 대한 예상 결과를 제공하지는 않습니다 (물론 예상 한 것에 따라 다르지만 0은 1보다 나에게 더 합리적입니다)
stijn

@stijn 잘 잡아. 상수에 긴 이중 리터럴 접미사를 추가하면 예제 문제가 해결되었지만 다른 정확한 예제가 있는지 알 수 없습니다.
kalaxy

1
btw 0.5 대신 0.49999999999999994를 추가하면 0.49999999999999994 및 5000000000000001.0 모두 입력으로 정상적으로 작동합니다. 그래도 모든 값에 맞는지 확실하지 않으며 이것이 궁극적 인 해결책이라는 진술을 찾을 수 없었습니다.
stijn

1
@stijn 두 정수 사이의 값이 정확히 반올림되는 방향을 신경 쓰지 않으면 모든 값에 괜찮습니다. 생각하지 않고 다음과 같은 경우를 분석하여이를 증명할 것입니다 : 0 <= d <0.5, 0.5 <= d <1.5, 1.5 <= d <2 ^ 52, d> = 2 ^ 52. 또한 단 정밀도 케이스를 철저히 테스트했습니다.
Pascal Cuoq

3
4.9 [conv.fpint]에 따르면, "잘린 값을 대상 유형으로 표시 할 수없는 경우 동작이 정의되지 않습니다." 따라서 이것은 약간 위험합니다. 다른 SO 답변은이를 강력하게 수행하는 방법을 설명합니다.
Tony Delroy

41

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

1
또한이 lroundllround통합 결과
sp2danny의

@ sp2danny : 또는 펑키 한 0으로부터의 타이 브레이크 대신 lrint현재 라운딩 모드를 사용하는 것이 좋습니다 round.
Peter Cordes

27

일반적으로 다음과 같이 구현됩니다. floor(value + 0.5) .

편집 : 내가 알고있는 적어도 3 개의 반올림 알고리즘이 있기 때문에 아마도 라운드라고 부를 수 없습니다 : 0으로 반올림, 가장 가까운 정수로 반올림 및 은행가 반올림 가장 가까운 정수에 반올림을 요청합니다.


1
다른 버전의 '라운드'를 구분하는 것이 좋습니다. 언제 어느 것을 고를 지 아는 것이 좋습니다.
xtofl

5
실제로 "올바르다"고 합리적으로 주장 할 수있는 다른 반올림 알고리즘이 있습니다. 그러나 floor (value + 0.5)는이 중 하나가 아닙니다. 0.49999997f 또는 동등한 double과 같은 일부 값의 경우 대답은 잘못되었습니다. 모두 0이어야한다는 데 동의하면 1.0으로 반올림됩니다. 자세한 내용은이 게시물을 참조하십시오 : blog.frama-c.com/index.php?post/2013/05/02/nearbyintf1
Bruce Dawson

14

우리 가보고있는 두 가지 문제가 있습니다 :

  1. 반올림 변환
  2. 유형 변환.

반올림 변환은 반올림 ± float / double을 가장 가까운 floor / ceil float / double로 반올림하는 것을 의미합니다. 문제가 여기서 끝날 수 있습니다. 그러나 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


수학이 정확하지 않을 수 있으므로 합병증을 사용 LONG_MIN-0.5하고 LONG_MAX+0.5도입합니다. 정확한 변환을 위해 정밀도를 LONG_MAX초과 할 수 있습니다 double. 또한 정확하게 표현할 수 있고 캐스트에 실패한 정확한 결과를 가질 수 있으므로 assert(x < LONG_MAX+0.5); (<vs <=)을 원할 것 입니다. 다른 코너 문제도 있습니다. LONG_MAX+0.5(x)+0.5LONG_MAX+1long
chux-복원 Monica Monica

함수를 호출하지 마십시오. round(double)이미 해당 이름의 표준 수학 라이브러리 함수 (C ++ 11)가 있으므로 혼동됩니다. std::lrint(x)가능한 경우 사용하십시오 .
Peter Cordes

11

특정 유형의 반올림도 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;
}

정수로 변환하는 경우에만 작동합니다.


2
Boost는 간단한 반올림 함수도 제공합니다. 내 대답을 참조하십시오.
Daniel Wolf

boost:numeric::RoundEven< double >::nearbyint정수를 원하지 않으면 직접 사용할 수도 있습니다 . @DanielWolf 참고 간단한 기능은 +0.5를 사용하여 구현되며 aka.nice에 의해 배치 된 문제가 있습니다
stijn

6

다음을 사용하여 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;
}

4
컴파일러의 int 크기가 기본적으로 1024 비트가 아니라면, 이것은 두 배로 정확하지 않을 것입니다.
aka.nice

나는 그것이 사용될 때 주어진 것이 허용된다고 생각한다. 만약 당신의 double value가 1.0 e + 19라면, 3 자리로 반올림하는 것은 의미가 없다.
Carl

3
확실하지만 질문은 일반적인 라운드에 대한 것이며, 어떻게 사용될 것인지 제어 할 수 없습니다. 천장과 바닥이 닿지 않는 곳에 라운드가 실패 할 이유가 없습니다.
aka.nice

이 범위 밖의 인수에 대해서는 정의되지 않은 동작이 있습니다 int. (x86에서 실제로 범위를 벗어난 FP 값 CVTTSD2SI0x80000000 정수 비트 패턴으로 생성 됩니다. 즉 INT_MIN, 다시로 변환됩니다 double.
Peter Cordes

5

요즘 C99 / C ++ 11 수학 라이브러리를 포함하는 C ++ 11 컴파일러를 사용하는 것은 문제가되지 않습니다. 그러나 문제는 다음과 같습니다. 어떤 반올림 함수를 선택합니까?

C99 / C ++ 11 round()은 종종 실제로 원하는 반올림 함수가 아닙니다 . 중간 경우 ( +-xxx.5000) 의 타이 브레이크로 0에서 반올림하는 펑키 반올림 모드를 사용합니다 . 반올림 모드를 구체적으로 원하거나 round()보다 빠른 C ++ 구현을 대상으로하는 rint()경우이를 사용하십시오 (또는이 질문에 대한 다른 답변 중 하나를 사용하여 동작을 에뮬레이션하여 액면 값을 취하고 해당 특정을 신중하게 재현합니다) 반올림 동작.)

round()반올림은 IEEE 브레이크 기본 반올림과 가장 가까운 모드로 의 반올림과 다릅니다 . 가장 가까운 경우에도 숫자의 평균 크기에서 통계적 편향을 피하지만 짝수로 편향됩니다.

현재 기본 반올림 모드를 사용하는 두 개의 수학 라이브러리 반올림 함수가 있습니다. std::nearbyint()std::rint()C99 / C ++ 11에 모두 추가되어 언제든지 사용할 수 있습니다 std::round(). 유일한 차이점은 nearbyintFE_INEXACT 를 발생 시키지 않는다는 것입니다.

선호 rint()성능상의 이유로 GCC를보다 쉽게 모두 인라인에게 그것을 그 소리, 그러나 GCC 결코 인라인 : nearbyint()(심지어와 -ffast-math)


x86-64 및 AArch64 용 gcc / clang

Matt Godbolt의 컴파일러 탐색기에 몇 가지 테스트 기능을 넣었습니다 . 여기에서 소스 + asm 출력 (여러 컴파일러의 경우)을 볼 수 있습니다. 컴파일러 출력을 읽는 방법에 대한 자세한 내용은 이 Q & A 및 Matt의 CppCon2017 강연을 참조하십시오 . “나의 컴파일러가 최근에 무엇을 했습니까? 컴파일러 뚜껑 언 볼팅” ,

FP 코드에서는 일반적으로 작은 함수를 인라인하는 것이 큰 승리입니다. 특히 표준 호출 규칙에 호출 보존 레지스터가없는 Windows가 아닌 경우 컴파일러는 XMM 레지스터의 FP 값을 XMM 레지스터에 유지할 수 없습니다.call . 따라서 실제로 asm을 모르더라도 라이브러리 함수에 대한 꼬리 호출인지 또는 하나 또는 두 개의 수학 명령에 인라인되었는지 쉽게 확인할 수 있습니다. 하나 또는 두 개의 명령어에 인라인하는 것은 함수 호출 (x86 또는 ARM의 특정 작업)보다 낫습니다.

x86에서 SSE4.1에 인라인하는 것은 roundsdSSE4.1 roundpd(또는 AVX vroundpd)로 자동 벡터화 할 수 있습니다 . (FP-> 정수 변환은 AVX512가 필요한 FP-> 64 비트 정수를 제외하고 팩형 SIMD 형식으로도 제공됩니다.)

  • std::nearbyint():

    • x86 clang : 단일 인라인으로 인라인 -msse4.1 .
    • 86 GCC : 만에 하나 INSN에 인라인 -msse4.1 -ffast-math, 오직 GCC 5.4에 이전 . 이 (어쩌면 그들이 정확하지 않은 예외를 억제 할 수 즉시 비트의 하나를 몰랐어요의 어떤 그 소리 사용하지만, 나이가 GCC가 같은 즉각적인에 관해서는 사용? 인라인 나중에 결코 gcc를하지 rint가 인라인 수행 할 때)
    • AArch64 gcc6.3 : 기본적으로 단일 인라인으로 인라인합니다.
  • std::rint:

    • x86 clang : 단일 인라인으로 인라인 -msse4.1
    • x86 gcc7 : 단일 인라인으로 인라인 -msse4.1 . (SSE4.1없이 여러 지침에 대한 인라인)
    • x86 gcc6.x 및 이전 버전 :을 사용하여 단일 인라인으로 인라인합니다 -ffast-math -msse4.1.
    • AArch64 gcc : 기본적으로 단일 인라인으로 인라인
  • std::round:

    • x86 clang : 인라인하지 않습니다
    • x86 gcc : 여러 명령어에 대한 인라인 -ffast-math -msse4.1 두 개의 벡터 상수가 필요합니다.
    • AArch64 gcc : 단일 명령어에 대한 인라인 (이 반올림 모드 및 IEEE 기본값 및 대부분의 기타에 대한 하드웨어 지원)
  • std::floor/ std::ceil/std::trunc

    • x86 clang : 단일 인라인으로 인라인 -msse4.1
    • x86 gcc7.x : 단일 인라인으로 인라인 -msse4.1
    • x86 gcc6.x 및 이전 버전 : 단일 인라인에 대한 인라인 -ffast-math -msse4.1
    • AArch64 gcc : 기본적으로 단일 명령에 대한 인라인

반올림 int/ long/ long long:

여기에는 두 가지 옵션이 있습니다 : lrint(like rintbut returns long또는 long longfor llrint) 또는 FP-> FP 반올림 함수를 사용한 다음 일반적인 방식으로 정수 유형으로 변환하십시오 (절단 사용). 일부 컴파일러는 다른 방식보다 한 가지 방식을 더 잘 최적화합니다.

long l = lrint(x);

int  i = (int)rint(x);

참고 int i = lrint(x)변환을 float하거나 double-> long먼저, 다음에 정수를 자릅니다int . 범위를 벗어난 정수의 경우 차이가 있습니다 .C ++에서는 정의되지 않은 동작이지만 x86 FP-> int 명령어에 대해 잘 정의되어 있습니다 (정확한 전파를 수행하는 동안 컴파일 타임에 UB를 보지 않으면 컴파일러가 방출합니다) 코드가 실행될 경우 중단되는 코드를 만들 수 있음).

86에서 정수 오버플 FP-> 정수 변환을 생성 INT_MIN하거나 LLONG_MIN(의 비트 패턴 0x8000000단지 부호 비트 세트로 또는 64 비트 상당). 인텔은이를 "정수 무한정"값이라고합니다. (참조 수동 입력 , 그것은 사용할 수 있다고 절단과 변환 () 부호있는 정수에 스칼라 배. SSE2 명령어를 32 비트 또는 64 비트 정수 대상 (64 비트 모드에서만).도 있습니다 현재 라운딩 (변환이 mode), 이것은 컴파일러가 방출하고 싶지만 불행히도 gcc와 clang은 없이는 그렇게하지 않습니다 .cvttsd2sicvtsd2si-ffast-math

또한 unsignedint / long에 대한 FP의 효율성은 x86에서 (AVX512없이) 덜 효율적입니다. 64 비트 컴퓨터에서 부호없는 32 비트로의 변환은 매우 저렴합니다. 64 비트 부호로 변환하고 자르기 만하면됩니다. 그러나 그렇지 않으면 상당히 느려집니다.

  • 유무에 관계없이 x86 clang -ffast-math -msse4.1: /에 (int/long)rint인라인 . (에 최적화를 놓쳤습니다 ). 전혀 인라인하지 않습니다.roundsdcvttsd2sicvtsd2silrint

  • x86 gcc6.x 및 이전 버전 -ffast-math: 인라인 방식

  • 86 gcc7없이 -ffast-math: (int/long)rint별도로 라운드와 회심은 (SSE4.1 2 개 총 지침을 사용하여, 다른 코드의 무리와 함께 대한 인라인 rint없이 roundsd). lrint인라인하지 않습니다.
  • 86 GCC 와 함께 -ffast-math : 모든 방법에 인라인 cvtsd2si(최적) , SSE4.1에 대한 필요가 없습니다.

  • AArch64 gcc6.3 미포함 -ffast-math: (int/long)rint2 가지 지시 사항에 대한 인라인. lrint인라인하지 않습니다

  • AArch64 gcc6.3 with -ffast-math: (int/long)rint에 대한 호출을 컴파일합니다 lrint. lrint인라인하지 않습니다. 우리가 얻지 못한 두 가지 명령 -ffast-math이 매우 느리지 않으면 이것은 놓친 최적화 일 수 있습니다 .

TODO : ICC와 MSVC도 Godbolt에서 사용할 수 있지만 이에 대한 결과는 보지 못했습니다. 편집을 환영합니다 ... 또한 : 컴파일러 / 버전으로 먼저 분해 한 다음 그 기능으로 더 유용합니까? 대부분의 사람들은 FP-> FP 또는 FP-> 정수 반올림을 얼마나 잘 컴파일하는지에 따라 컴파일러를 전환하지 않을 것입니다.
Peter Cordes

2
rint()그것이 가능한 선택 을 권장하기 위해 +1 , 일반적으로 그렇습니다. 나는 그 이름 round()이 일부 프로그래머에게 이것이 원하는 것임을 암시한다고 생각 하지만 rint()신비한 것처럼 보입니다. 참고 round()는 "펑키"반올림 모드를 사용하지 않습니다으로 반올림 넥타이는 멀리 공식 IEEE-754 (2008) 반올림 모드입니다. 그것은 그 호기심의 nearbyint()그것을 크게 같은 것을 주어, 인라인되지 않습니다 rint(), 그리고해야 동일한 아래 -ffast-math조건. 그것은 나에게 버그처럼 보인다.
njuffa

4

주의하십시오 floor(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과 같은 솔루션을 사용하십시오.

내 자신의 강력한 버전은 다음과 같습니다.

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

floor (x + 0.5)를 피하는 또 다른 이유는 여기에 있습니다 .


2
다운 보트에 대해 알고 싶습니다. 동점은 가장 가까운 짝수보다는 0에서 멀어지기 때문입니까?
aka.nice

1
참고 : C 사양에 "현재 반올림 방향에 관계없이 반올림 사례가 0에서 멀어짐"이 표시되므로 홀수 / 짝수에 관계없이 반올림이 준수됩니다.
chux-복원 Monica Monica

4

궁극적으로 함수 의 double출력 을로 변환하려면 이 질문에 허용되는 솔루션은 다음과 같습니다.round()int

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

이것은 균일하게 임의의 값으로 전달 될 때 내 컴퓨터 에서 약 8.88ns로 작동 합니다.

아래는 내가 말할 수있는 한 기능적으로 동일하지만 내 컴퓨터 에서 2.48ns로 클럭 하면 상당한 성능 이점이 있습니다.

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

더 나은 성능의 이유 중 하나는 건너 뛴 분기입니다.


이 범위 밖의 인수에 대해서는 정의되지 않은 동작이 있습니다 int. (x86에서 실제로 범위를 벗어난 FP 값 CVTTSD2SI0x80000000 정수 비트 패턴으로 생성 됩니다. 즉 INT_MIN, 다시로 변환됩니다 double.
Peter Cordes

2

아무것도 구현할 필요가 없으므로 많은 답변이 정의, 함수 또는 메소드와 관련되는 이유를 모르겠습니다.

C99에서

형식 일반 매크로에 대한 다음과 헤더 <tgmath.h>가 있습니다.

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

이것을 컴파일 할 수 없다면 아마도 수학 라이브러리를 생략했을 것입니다. 이와 비슷한 명령은 내가 가진 모든 C 컴파일러에서 작동합니다 (여러 개).

gcc -lm -std=c99 ...

C ++ 11에서

IEEE 배정 밀도 부동 소수점에 의존하는 #include <cmath>에는 다음과 같은 추가 과부하가 있습니다.

#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 커뮤니티에서 오류나 경고를 생성하지 않습니다.

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

서 수부

T가 short, int, long 또는 다른 서수 인 두 서수를 나눌 때 반올림 식은 다음과 같습니다.

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

정확성

부동 소수점 연산에서 이상한 모양의 부정확성이 나타나는 것은 의심의 여지가 없지만 숫자가 나타날 때만 발생하며 반올림과는 거의 관련이 없습니다.

소스는 부동 소수점 숫자의 IEEE 표현 가수에서 유효 숫자의 숫자 일뿐만 아니라 인간으로서의 십진수 사고와 관련이 있습니다.

10은 5와 2의 곱이고 5와 2는 비교적 소수입니다. 따라서 IEEE 부동 소수점 표준을 모든 이진 디지털 표현에 대해 십진수로 완벽하게 표현할 수는 없습니다.

반올림 알고리즘에는 문제가 없습니다. 유형 선택 및 계산 설계, 데이터 입력 및 숫자 표시 중에 고려해야 할 수학적 현실입니다. 응용 프로그램에 이러한 10 진수 이진 변환 문제를 나타내는 숫자가 표시되면 응용 프로그램이 디지털 현실에는 존재하지 않는 정확도를 시각적으로 나타내는 것이므로 변경해야합니다.


1
"왜 그렇게 많은 답변이 정의, 함수 또는 메소드와 관련이 있는지 잘 모르겠습니다." C ++ 11이 아직 나오지 않았다는 요청을 살펴보십시오. ;)
jaggedSpire

@jaggedSpire, 오늘날 가장 일반적으로 사용되는 컴파일러의 맥락에서 모든 높은 점수의 답변이 더 이상 사용되지 않고 오도되기 때문에 적절하다고 생각되면 엄지 손가락을 줘야합니다.
FauChristian

2

기능 double round(double)을 사용하여 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.0입니다
  • -2.3의 라운드는 -2.0입니다
  • -3.8의 라운드는 -4.0입니다
  • -5.0의 라운드는 -5.0입니다

2
이것은 좋은 해결책입니다. 나는 -1.5에서 -1.0으로 반올림하는 것이 표준인지 확실하지 않지만, symetry에 의해 -2.0을 기대할 것입니다. 또한 선두 경비원의 요점을 볼 수 없습니다. 처음 두 명은 제거 할 수 있습니다.
aka.nice

2
ISO / IEC 10967-2 표준, open-std.org/jtc1/sc22/wg11/docs/n462.pdf 및 부록 B.5.2.4에서 반올림 함수는 실제로 대칭이어야합니다. rounding_F (x) = neg_F (rounding_F (neg_F (x)))
aka.nice

C ++ 11 rint()또는에 비해 속도가 느리지 nearbyint()만 실제로 올바른 반올림 기능을 제공하는 컴파일러를 사용할 수없고 성능보다 정밀도가 더 필요한 경우 ...
Peter Cordes

1

C ++ 11 표준을 지원하는 환경에서 코드를 컴파일 할 수 있어야하지만이를 지원하지 않는 환경에서 동일한 코드를 컴파일 할 수 있어야하는 경우 함수 매크로를 사용하여 std 중에서 선택할 수 있습니다. :: round () 및 각 시스템에 대한 사용자 정의 함수. C ++ 11 호환 컴파일러를 전달 -DCPP11하거나 /DCPP11내장 버전 매크로를 사용하여 다음과 같이 헤더를 만드십시오.

// 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를 참조하십시오. .

이는 -0.0에 대한 부호 비트 보존을 포함하여 C ++ 11과 호환되지 않는 환경에서 std :: round ()와 비슷합니다. 그러나 약간의 성능 저하가 발생할 수 있으며 0.49999999999999994와 같은 알려진 "문제점"부동 소수점 값 또는 이와 유사한 값을 반올림하는 데 문제가있을 수 있습니다.

또는 C ++ 11 호환 컴파일러에 액세스 할 수 있다면 std :: round ()를 얻을 수 있습니다. <cmath> 헤더 와서 아직 정의되지 않은 경우 함수를 정의하는 자체 헤더를 만들 수 있습니다. 그러나 특히 다중 플랫폼 용으로 컴파일해야하는 경우에는 최적의 솔루션이 아닐 수 있습니다.


1

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

1
내 대답 에서 지적했듯이 추가 0.5는 모든 경우에 작동하지 않습니다. 적어도 오버플로 문제를 처리하므로 정의되지 않은 동작을 피하십시오.
Shafik Yaghmour

1

의견과 다른 답변에서 지적했듯이 ISO C ++ 표준 라이브러리는 추가하지 않았습니다. round() ISO C99 표준 수학 라이브러리를 참조하여이 함수를 가져 왔을 때 ISO C ++ 11까지 .

[½, ub ]의 양수 피연산자의 round(x) == floor (x + 0.5)경우, ub 는 IEEE-754 (2008)에 매핑 된 경우 2 23 , floatIEEE-754 (2008) binary32에 매핑 된 경우 2 52 입니다 . 숫자 23과 52 는이 두 부동 소수점 형식 의 저장된 가수 비트 수에 해당합니다 . [+0, ½)의 양의 피연산자 및 ( ub , + ∞]의 양의 피연산자에 대한 함수가 x 축에 대해 대칭이므로 음수 인수 는에 따라 처리 될 수 있습니다 .doublebinary64round(x) == 0round(x) == xxround(-x) == -round(x)

이것은 아래의 컴팩트 코드로 이어집니다. 다양한 플랫폼에서 합리적인 수의 기계 명령어로 컴파일됩니다. my_roundf()약 12 개의 명령이 필요한 GPU에서 가장 컴팩트 한 코드를 관찰했습니다 . 프로세서 아키텍처 및 툴체인에 따라이 부동 소수점 기반 접근 방식은 다른 답변 에서 참조 된 newlib의 정수 기반 구현보다 빠르거나 느릴 수 있습니다 .

나는 시험 my_roundf()newlib에 대해 철저하게 roundf()모두 인텔 컴파일러 버전 (13)를 사용하여 구현 /fp:strict하고 /fp:fast. 나는 또한 newlib에 버전이 일치하는지 확인 roundf()에서 mathimf인텔 컴파일러의 라이브러리입니다. 배정도 round()에서는 철저한 테스트가 불가능 하지만 코드는 단 정밀도 구현과 구조적으로 동일합니다.

#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <string.h>
#include <math.h>

float my_roundf (float x)
{
    const float half = 0.5f;
    const float one = 2 * half;
    const float lbound = half;
    const float ubound = 1L << 23;
    float a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floorf (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

double my_round (double x)
{
    const double half = 0.5;
    const double one = 2 * half;
    const double lbound = half;
    const double ubound = 1ULL << 52;
    double a, f, r, s, t;
    s = (x < 0) ? (-one) : one;
    a = x * s;
    t = (a < lbound) ? x : s;
    f = (a < lbound) ? 0 : floor (a + half);
    r = (a > ubound) ? x : (t * f);
    return r;
}

uint32_t float_as_uint (float a)
{
    uint32_t r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float uint_as_float (uint32_t a)
{
    float r;
    memcpy (&r, &a, sizeof(r));
    return r;
}

float newlib_roundf (float x)
{
    uint32_t w;
    int exponent_less_127;

    w = float_as_uint(x);
    /* Extract exponent field. */
    exponent_less_127 = (int)((w & 0x7f800000) >> 23) - 127;
    if (exponent_less_127 < 23) {
        if (exponent_less_127 < 0) {
            /* Extract sign bit. */
            w &= 0x80000000;
            if (exponent_less_127 == -1) {
                /* Result is +1.0 or -1.0. */
                w |= ((uint32_t)127 << 23);
            }
        } else {
            uint32_t 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 so raise FE_INVALID by adding */
            return x + x;
        } else {
            return x;
        }
    }
    x = uint_as_float (w);
    return x;
}

int main (void)
{
    uint32_t argi, resi, refi;
    float arg, res, ref;

    argi = 0;
    do {
        arg = uint_as_float (argi);
        ref = newlib_roundf (arg);
        res = my_roundf (arg);
        resi = float_as_uint (res);
        refi = float_as_uint (ref);
        if (resi != refi) { // check for identical bit pattern
            printf ("!!!! arg=%08x  res=%08x  ref=%08x\n", argi, resi, refi);
            return EXIT_FAILURE;
        }
        argi++;
    } while (argi);
    return EXIT_SUCCESS;
}

int너비가 16 비트 이상 이라고 가정하지 않도록 편집했습니다 . 물론 float4 바이트 IEEE754 2 진 32 라고 가정합니다 . C ++ 11 static_assert또는 매크로 #ifdef/ #error확인 가능합니다. (물론 C ++ 11을 사용할 수있는 경우 std::round, 또는 현재 반올림 모드 std::rint에 gcc 및 clang과 잘 어울리는 인라인을 사용해야 합니다).
Peter Cordes

BTW, gcc -ffast-math -msse4.1인라인 std::round()add( AND(x, L1), OR(x,L2), 다음 roundsd. 즉 round, 측면에서 상당히 효율적으로 구현 됩니다 rint. 당신이있는 경우에 있기 때문에 C ++ 소스에서 수동으로이 작업을 수행 할 이유가 없다 std::rint()또는 std::nearbyint()당신은 또한이 std::round(). Godbolt 링크와 다른 gcc / clang 버전의 인라인 여부에 대한 내 대답을 참조하십시오.
Peter Cordes

@PeterCordes 나는 round()효율적 으로 구현하는 방법을 잘 알고 있습니다 rint()(후자는 일대일 모드에서 동작 할 때) .CUDA 표준 수학 라이브러리를 위해 구현했습니다. 그러나이 질문 round()은 C ++ 11 이전에 C ++ 로 구현하는 방법을 묻는 것처럼 보였으 므로 및 rint()만 사용할 수는 없습니다 . floor()ceil()
njuffa

@PeterCordes 죄송합니다. round()0으로 반올림 모드 rint()에서 쉽게 합성됩니다 . 첫 커피 전에 응답하지 않아야합니다. trunc()
njuffa

1
@PeterCordes OP는 특정 반올림 동작이 필요하지 않을 것입니다 round(). 대부분의 프로그래머는 단순히 사이의 구별을 인식하지 못합니다 round()rint()에 가장 가까운 수로 반올림에도, 후자는 일반적으로 하드웨어 때문에보다 효율적으로 직접 제공된다; 나는 가이드 인식 프로그래머를 만들기 위해 프로그래밍 CUDA에서 밖으로 철자 : "결과는 부동 소수점 숫자는 단 정밀도 인 상태, 부동 소수점 연산 정수로 단 정밀도를 반올림하는 권장되는 방법 rintf()이 아니라을 roundf()".
njuffa

0

x86 아키텍처 및 MS VS 특정 C ++에 대해 다음과 같은 라운드 인 asm 구현을 사용합니다.

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

UPD : 이중 값을 반환

__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

결과 값은 배정도의 부동 소수점 값이어야합니다.
truthseeker

@ truthseeker : 예, 필요한 유형의 반환 값을보아야했습니다. "UPD"를 참조하십시오.
Aleksey F.

컴파일러는 희망적으로 인라인 rint()또는 nearbyint()SSE4.1 roundsd명령 또는 x87 frndint명령으로 인라인 될 것입니다.이 명령은 레지스터의 데이터에서이 인라인 asm을 사용하는 데 필요한 두 개의 저장 / 재로드 라운드 트립보다 훨씬 빠릅니다. MSVC 인라인 asm frndint은 레지스터에서 입력을 얻을 수있는 방법이 없기 때문에 단일 명령을 래핑하는 데 많은 시간을 소비 합니다. 결과를 함수의 끝에 사용하면 결과 st(0)를 리턴하는 방법으로 신뢰할 수 있습니다. 분명히 eax그것은 asm을 포함하는 함수를 인라인 할 때조차 정수에 안전 합니다.
Peter Cordes

@PeterCordes 최신 최적화를 환영합니다. 그러나 SSE4.1은 존재하지 않았기 때문에 사용할 수 없었습니다. 저의 목적은 2000 년대의 구형 인텔 P3 또는 P4 제품군에서도 작동 할 수있는 최소 라운드 구현을 제공하는 것이 었습니다.
Aleksey F.

P3에는 SSE2도 없기 때문에 컴파일러는 이미 x87을 사용 double하므로를 frndint위해 자체를 생성 할 수 있어야합니다 rint(). 컴파일러가 SSE2를 사용 double하는 경우 XMM 레지스터에서 x87로 튀는 것을 되 돌리는 것이 가치가 없을 수 있습니다.
Peter Cordes

0

부동 소수점 값을 "n"소수점 이하 자릿수로 반올림하는 가장 좋은 방법은 O (1) 시간과 다음과 같습니다.

값을 3 자리로 반올림해야합니다 (예 : n = 3).

float a=47.8732355;
printf("%.3f",a);

-4
// Convert the float to a string
// We might use stringstream, but it looks like it truncates the float to only
//5 decimal points (maybe that's what you 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");

비효율적 인 더러운 변환 방법 일지 모르지만 도대체 작동합니다. 실제 플로트에 적용되기 때문에 좋습니다. 시각적으로 출력에 영향을 미치지 않습니다.


이것은 유감스럽게도 비효율적이며 가장 가까운 반올림 대신 항상 후행 숫자를 버림으로써 잘립니다.
Peter Cordes

-6

나는 이걸했다:

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

3
10 ^ place에서 이항 연산자 ^ 대신 pow (10, place)을 의미하지 않습니까? 내 컴퓨터의 10 ^ 2는 8을줍니다! 그럼에도 불구하고 내 Mac 10.7.4 및 gcc에서는 코드가 작동하지 않아 원래 값을 반환합니다.
Pete855217
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.