我必须使用非科学(即无尾数/指数/ E)字符串转换十进制数字。我的代码如下所示:
/*!
\brief Converts a <em>XML Schema Decimal</em>
*/
char *ToDecimal(double val) const
{
const size_t nMax = 200;
char *doubleStr = new char[nMax];
sprintf(doubleStr, "%1.6f", val);
return doubleStr;
}
问题是,当输入val
为1
时,函数返回1.000000
,但我希望输出1
。此外,如果我将代码更改为sprintf(doubleStr, "%1.0f", val);
,则会正确输出1
,但如果输入val
更改为0.000005
,则输出为0
,并且我希望输出结果为0.000005
。所以基本上我希望所有输出都尽可能短,并删除所有无法识别的0
。这可能是sprintf
吗?我想用这个功能支持3.4E +/- 38范围。
答案 0 :(得分:1)
由于这是标记的C ++,我假设您可以使用C中没有的C ++功能(如果没有,请告诉我,我将删除此答案)。
首先,我建议使用std::string
代替char*
(这可以让你从管理缓冲区的内存中解放出来)?其次,我建议使用ostringstream
进行转换:
#include <sstream>
std::string ToDecimal(double val) {
std::ostringstream oss;
oss << val;
return oss.str();
}
答案 1 :(得分:1)
事实证明,c ++ iostreams(特别是ostringstream
)比sprintf
更适合您的任务。
使用std::fixed
操纵器禁用科学记数法。使用std::setprecision
指定精度(小数点后的字符数)。在您的情况下,45个位置的精度似乎足以代表所有float
个数字。
#include <sstream>
#include <string>
#include <iostream>
#include <iomanip>
std::string convert(double x)
{
std::ostringstream buffer;
buffer << std::fixed << std::setprecision(45) << x;
std::string result = buffer.str();
return result;
}
此外,要清除结果,请删除任何尾随零。
size_t i = result.find_last_not_of('0');
if (result[i] != '.')
++i;
result.erase(i);
注意:尾随零的清理仅适用于可精确表示的数字(如0.75或0.03125):例如,数字0.1将转换为0.10000000000000000555111512312578270211815834
。人们可以使用非常数精度(取决于数字的大小),但要做到这一点非常棘手。
相反,可以使用以下丑陋(和缓慢)的黑客攻击:尝试将字符串的开头转换回double
,如果结果等于初始数字,则剪切字符串。
size_t i;
for (i = 1; i < result.size(); ++i)
{
std::istringstream cut(result.substr(0, i));
double temp;
cut >> temp; // the verbose syntax could fit into one line
if (temp == x) // by using boost::lexical_cast
break;
}