我想将一个浮点值格式化为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;
如果有人知道更好的方法…