指定された精度と小数点以下の桁数でfloatを文字列に変換しますか?


88

精度と小数点以下の桁数を指定しながら、C ++でfloatを文字列に変換するにはどうすればよいですか?

例えば: 3.14159265359 -> "3.14"


指定した精度で一時フロートを作成し、それを文字列に変換してみませんか?
ギラッド2015年

@Gilad「tempfloat」には「指定された精度」がなく、そのようなアプローチが機能しない場合があります。この質問は基本的に「 '%.2f'形式に相当するものは何ですか」と尋ねるようなものですか?
user2864740 2015年

1
これがIOに必要なだけの場合は、stackoverflow.com / questions / 14432043 / c-float-formattingを参照してください。
user2864740 2015年

回答:


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


ために 技術的な目的の変換、C ++ 17の定義するXMLまたはJSONファイル内のデータを格納するように、to_chars機能の家族を。

準拠したコンパイラ(執筆時点では不足しています)を想定すると、次のようなものが考えられます。

#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私はそれがより速くなると強く信じています。それが私が最初にこの答えをした理由です。
コロンボ2015年

@MatsPetersson測定(GCC 4.8.1、-O2)を実行しました。これは、snprintfが実際にかかる時間が17/22倍少ないことを示しています。すぐにコードをアップロードします。
コロンボ2015年

@MatsPetersson私のベンチマークにはおそらく欠陥がありますが、stringstreamバージョンは1000000回の反復でsnprintfバージョンの2倍の時間がかかります(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'sに似ていますが{}、の代わりに区切り文字として使用するPythonのようなフォーマット文字列構文を使用し%ます。


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文字後にすべての文字を切り取ります。


唯一のことは、この方法では実際に数値を丸めていないということです。
ChrCury 7819

1
@ ChrCury78私の答えで述べたように、これは切り捨てられるだけです。通常の丸めが必要な場合は、値に続いてダイゲットに5を追加するだけです。たとえばnumber + 0.005私の場合。
セバスチャン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以降では、表示する浮動小数点の後の桁数として2番目のパラメーターを指定する必要があります。現在、デフォルトは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.