정밀도 및 소수 자릿수가 지정된 문자열로 float를 변환 하시겠습니까?


88

정밀도 및 소수 자릿수를 지정하는 동안 C ++에서 float를 문자열로 어떻게 변환합니까?

예를 들면 : 3.14159265359 -> "3.14"


원하는 지정된 정밀도로 임시 부동 소수점을 만든 다음 문자열로 변환하지 않는 이유는 무엇입니까?
Gilad 2015 년

@Gilad 'temp float'에는 '지정된 정밀도'가 없으며 그러한 접근 방식이 무너지는 경우가 있습니다. 이 질문은 기본적으로 " '% .2f'형식과 동등한 것은 무엇입니까?"라고 묻는 것과 같습니다.
user2864740

1
IO에만 필요한 경우 stackoverflow.com/questions/14432043/c-float-formatting을 참조하십시오 .
user2864740

답변:


131

일반적인 방법은 다음을 사용하는 것입니다 stringstream.

#include <iomanip>
#include <sstream>

double pi = 3.14159265359;
std::stringstream stream;
stream << std::fixed << std::setprecision(2) << pi;
std::string s = stream.str();

고정 참조

고정 부동 소수점 표기법 사용

str 스트림 의 floatfield형식 플래그를로 설정합니다 .fixed

가로 floatfield설정 fixed되면 부동 소수점 값이 고정 소수점 표기법을 사용하여 기록됩니다. 값은 정밀도 필드 ( precision)에 지정된대로 소수점 부분에 지수 부분없이 정확하게 숫자로 표시됩니다 .

setprecision .


에 대한 기술적 인 목적의 변환 XML 또는 JSON 파일, C ++ (17 명)을 정의의 데이터 저장과 같은, 바꿀수 기능의 가족.

준수 컴파일러 (작성 당시 부족함)를 가정하면 다음과 같은 것을 고려할 수 있습니다.

#include <array>
#include <charconv>

double pi = 3.14159265359;
std::array<char, 128> buffer;
auto [ptr, ec] = std::to_chars(buffer.data(), buffer.data() + buffer.size(), pi,
                               std::chars_format::fixed, 2);
if (ec == std::errc{}) {
    std::string s(buffer.data(), ptr);
    // ....
}
else {
    // error handling
}

28

이런 종류의 작업을 수행하는 일반적인 방법은 "문자열로 인쇄"하는 것입니다. C ++에서는 std::stringstream다음과 같은 것을 사용하는 것을 의미합니다 .

std::stringstream ss;
ss << std::fixed << std::setprecision(2) << number;
std::string mystring = ss.str();

12

또 다른 옵션은 snprintf다음과 같습니다.

double pi = 3.1415926;

std::string s(16, '\0');
auto written = std::snprintf(&s[0], s.size(), "%.2f", pi);
s.resize(written);

데모 . 오류 처리를 추가해야합니다 (예 :written < 0.


snprintf이 경우 왜 더 좋을까요? 설명해주세요 ... 확실히 빠르지는 않을 것입니다. 더 적은 코드를 생성합니다. [printf 구현을 작성했습니다. 코드가 2000 줄 미만으로 상당히 콤팩트하지만 매크로 확장을 사용하면 약 2500 줄이됩니다.]
Mats Petersson

1
@MatsPetersson 나는 그것이 더 빠를 것이라고 강력하게 믿습니다. 이것이 제가 처음에이 답변을 만든 이유입니다.
Columbo

@MatsPetersson 나는 snprintf가 실제로 시간이 적게 걸리는 것을 나타내는 측정 (GCC 4.8.1, -O2)을 17/22로 수행했습니다. 곧 코드를 업로드하겠습니다.
Columbo 2015 년

@MatsPetersson 내 벤치 마크에 결함이있을 수 있지만 stringstream 버전은 1000000 반복에서 snprintf 버전보다 두 배 더 오래 걸립니다 (Clang 3.7.0, libstdc ++, -O2).

나도 몇 가지 측정을 수행했으며 (적어도 Linux에서는) stringstream과 snprintf가 동일한 기본 __printf_fp기능을 사용하는 것처럼 보일 것 stringstream입니다. 실제로 필요하지 않기 때문에에서 훨씬 더 오래 걸리는 것은 다소 이상합니다 .
Mats Petersson 2015 년

9

{fmt} 라이브러리fmt::format함수를 사용할 수 있습니다 .

#include <fmt/core.h>

int main()
  std::string s = fmt::format("{:.2f}", 3.14159265359); // s == "3.14"
}

2정밀도는 어디에 있습니까 ?

이 포맷 기능은 C ++의 표준화를 위해 제안되었습니다 : P0645 . 두 P0645 및 {FMT는} 비슷한 형식 파이썬 같은 문자열 구문을 사용 printf의하지만 용도 {}구분 기호로 대신을 %.


7

여기 std 만 사용하는 솔루션입니다. 그러나 이것은 내림 만합니다.

    float number = 3.14159;
    std::string num_text = std::to_string(number);
    std::string rounded = num_text.substr(0, num_text.find(".")+3);

결과 rounded:

3.14

이 코드는 전체 float를 문자열로 변환하지만 "."뒤의 모든 문자를 2 자씩 자릅니다.


유일한 것은 이런 식으로 실제로 숫자를 반올림하지 않는다는 것입니다.
ChrCury78

1
내 대답에 명시된대로 @ ChrCury78은 내림합니다. 정상적인 반올림을 원하면 값 다음에 5를 더하면됩니다. 예를 들어 number + 0.005내 경우.
Sebastian R.

2

여기에서는 부동 숫자를 문자열로 변환 할 때 피하고 싶은 부정적인 예를 제공합니다.

float num=99.463;
float tmp1=round(num*1000);
float tmp2=tmp1/1000;
cout << tmp1 << " " << tmp2 << " " << to_string(tmp2) << endl;

당신은 얻을

99463 99.463 99.462997

참고 : num 변수는 99.463에 가까운 값이 될 수 있으며 동일한 출력을 얻을 수 있습니다. 요점은 편리한 c ++ 11 "to_string"함수를 피하는 것입니다. 이 함정을 빠져 나가는데 시간이 좀 걸렸습니다. 가장 좋은 방법은 stringstream 및 sprintf 메서드 (C 언어)입니다. C ++ 11 이상에서는 표시 할 부동 소수점 뒤의 자릿수로 두 번째 매개 변수를 제공해야합니다. 현재 기본값은 6입니다. 다른 사람들이이 주제에 시간을 낭비하지 않도록 이것을 설정하고 있습니다.

첫 번째 버전을 작성했습니다. 수정해야 할 버그를 찾으면 알려주세요. iomanipulator로 정확한 동작을 제어 할 수 있습니다. 내 기능은 소수점 이하 자릿수를 표시하는 기능입니다.

string ftos(float f, int nd) {
   ostringstream ostr;
   int tens = stoi("1" + string(nd, '0'));
   ostr << round(f*tens)/tens;
   return ostr.str();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.