浮動小数点値を有効桁数 n にフォーマットしたいのですが、科学表記法を使用しないでください (たとえそれが短くても)。
フォーマット仕様%f
は有効数字を扱っておらず、%g
科学的表記法を提供することがあります (これは私の使用には不適切です)。
フォームの値が必要です"123", "12.3", "1.23" or "0.000000123"
。
C++ または boostを使用してこれを行うエレガントな方法はありますか?
浮動小数点値を有効桁数 n にフォーマットしたいのですが、科学表記法を使用しないでください (たとえそれが短くても)。
フォーマット仕様%f
は有効数字を扱っておらず、%g
科学的表記法を提供することがあります (これは私の使用には不適切です)。
フォームの値が必要です"123", "12.3", "1.23" or "0.000000123"
。
C++ または boostを使用してこれを行うエレガントな方法はありますか?
私が知っている(そしてそれを自分のコードで使用する)最良の方法は
#include <string>
#include <math.h>
#include <sstream>
#include <iomanip>
int round(double number)
{
return (number >= 0) ? (int)(number + 0.5) : (int)(number - 0.5);
}
std::string format(double f, int n)
{
if (f == 0) {
return "0";
}
int d = (int)::ceil(::log10(f < 0 ? -f : f)); /*digits before decimal point*/
double order = ::pow(10., n - d);
std::stringstream ss;
ss << std::fixed << std::setprecision(std::max(n - d, 0)) << round(f * order) / order;
return ss.str();
}
c++11 には std::round があるため、私のバージョンの新しいコンパイラは必要ありません。
ここで私が利用しているトリックは、基数 10 の対数を使用して小数の前の桁数をカウントし、これを必要な精度から差し引くことによって、必要な精度を取得することです。
@Mats Petersson の要件も満たしているため、すべての場合に機能します。
私が気に入らないのは、最初にゼロをチェックすることです (そのため、ログ機能は爆発しません)。この回答の改善/直接編集の提案は大歓迎です。
std::fixed
そしてstd::setprecision
(そして<iomanip>
一般的に)あなたの友達です。
std::cout << 0.000000123 << '\n';
プリント1.23e-07
と
std::cout << std::setprecision(15) << std::fixed << 0.000000123 << '\n';
版画0.000000123000000
浮動小数点数には精度が限られていることを覚えておいてください。
std::cout << std::fixed << 123456789012345678901234567890.0 << '\n';
印刷されます123456789012345677877719597056.000000
(おそらくあなたが望むものではありません)
自分で末尾のゼロを削除する必要があると思います:
string trimString(string str)
{
string::size_type s;
for(s=str.length()-1; s>0; --s)
{
if(str[s] == '0') str.erase(s,1);
else break;
}
if(str[s] == '.') str.erase(s,1);
return str;
}
使用法 :
double num = 0.000000123;
stringstream ss;
ss << num;
ss.str("");
ss << std::setprecision(15) << std::fixed << num; // outputs 0.000000123000000
string str;
ss >> str;
str = trimString(str);
cout << str << endl; // outputs 0.000000123
まとめる :
string format(int prec, double d) {
stringstream ss;
ss << d;
ss.str("");
ss << std::setprecision(prec) << std::fixed << d;
string str;
ss >> str;
string::size_type s;
for(s=str.length() - 1; s > 0; --s)
{
if(str[s] == '0') str.erase(s,1);
else break;
}
if(str[s] == '.') str.erase(s,1);
return str;
}
使用法 :
double num = 0.000000123;
cout << format(15, num) << std::endl;
誰かがより良い方法を知っていれば...