【问题标题】:sprintf too many/few decimalssprintf 小数点太多/小数点
【发布时间】:2013-03-24 19:35:38
【问题描述】:

我必须使用非科学(即无尾数/指数/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;
}

问题是当输入val1 然后函数返回1.000000 但我希望输出1。另外,如果我将代码更改为sprintf(doubleStr, "%1.0f", val);,那么它会正确输出1,但如果输入val 更改为0.000005,则输出为0,我希望输出为@987654332 @。所以基本上我希望所有输出尽可能短,并删除所有不必要的0sprintf 可以做到这一点吗?我想用这个函数支持 3.4E +/- 38 范围。

【问题讨论】:

  • 那么如果输入是1e-30,你希望输出是0.000000000000000000000000000001吗?
  • 您必须编写代码将其转换为字符串并去除零并返回字符串。如果你想让它改变,你还必须传递位置的数量,因为当然 0.1 作为常数实际上并不等于 0.1。
  • @anatolyg 是的,一直到 3.4E-38。尝试实现对 XML Schema Decimal 的支持。 w3.org/TR/xmlschema-2/#decimal-lexical-representation

标签: c++ printf


【解决方案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;
}

【讨论】:

  • 使用 VC++ 2012 std::setprecision() 必须xFLT_MIN 时至少设置为 46 - 否则它只会返回 0
【解决方案2】:

由于这是标记为 C++,我假设您可以使用 C 中不可用的 C++ 功能(如果没有,请告诉我,我将删除此答案)。

首先,我建议使用std::string 而不是char*(这可以让您从管理缓冲区的内存中解放出来)?其次,我建议使用ostringstream 进行转换:

#include <sstream>

std::string ToDecimal(double val) {
    std::ostringstream oss;
    oss << val;
    return oss.str();
}

【讨论】:

  • +1 表示std::ostringstream,但你没有提到std::fixedstd::setprecision 所以我接受了anatolyg 的回答。谢谢。
  • @Inge Henriksen:很公平。没有难过的感觉;-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多