如何按以下方式格式化double? 我用C++,我想用下面的方法来格式化双打。我曾尝试使用stringstream来处理“固定”和“科学”问题,但我无法实现预期的输出 double d = -5; // print "-5" double d = 1000000000; // print "1000000000" double d = 3.14; // print "3.14" double d = 0.00000000001; // print "0.00000000001" // Floating point error is acceptable: double d = 10000000000000001; // print "10000000000000000"

如何按以下方式格式化double? 我用C++,我想用下面的方法来格式化双打。我曾尝试使用stringstream来处理“固定”和“科学”问题,但我无法实现预期的输出 double d = -5; // print "-5" double d = 1000000000; // print "1000000000" double d = 3.14; // print "3.14" double d = 0.00000000001; // print "0.00000000001" // Floating point error is acceptable: double d = 10000000000000001; // print "10000000000000000",c++,c++11,string-formatting,C++,C++11,String Formatting,按照要求,以下是我尝试过的东西: #include <iostream> #include <string> #include <sstream> #include <iomanip> using namespace std; string obvious_format_attempt1( double d ) { stringstream ss; ss.precision(15); ss << d;

按照要求,以下是我尝试过的东西:

#include <iostream>
#include <string>
#include <sstream>
#include <iomanip>

using namespace std;

string obvious_format_attempt1( double d )
{
    stringstream ss;
    ss.precision(15);
    ss << d;
    return ss.str();
}

string obvious_format_attempt2( double d )
{
    stringstream ss;
    ss.precision(15);
    ss << fixed;
    ss << d;
    return ss.str();
}

int main(int argc, char *argv[]) 
{
    cout << "Attempt #1" << endl;
    cout << obvious_format_attempt1(-5) << endl;
    cout << obvious_format_attempt1(1000000000) << endl;
    cout << obvious_format_attempt1(3.14) << endl;
    cout << obvious_format_attempt1(0.00000000001) << endl;
    cout << obvious_format_attempt1(10000000000000001) << endl;

    cout << endl << "Attempt #2" << endl;
    cout << obvious_format_attempt2(-5) << endl;
    cout << obvious_format_attempt2(1000000000) << endl;
    cout << obvious_format_attempt2(3.14) << endl;
    cout << obvious_format_attempt2(0.00000000001) << endl;
    cout << obvious_format_attempt2(10000000000000001) << endl;

    return 0;
}

程序无法知道如何按照您所描述的方式格式化数字,除非您编写一些代码以某种方式分析数字,即使这样也可能相当困难

这里需要的是知道源代码中的输入格式,一旦编译器将十进制输入源代码转换为二进制格式以存储在可执行文件中,这种格式就会丢失

一种可行的替代方法是输出到
stringstream
,然后从中修改输出以去除尾随的零。大概是这样的:

string obvious_format_attempt2( double d )
{
    stringstream ss;
    ss.precision(15);
    ss << fixed;
    ss << d;
    string res = ss.str();
    // Do we have a dot?
    if ((string::size_type pos = res.rfind('.')) != string::npos)
    {
       while(pos > 0 && (res[pos] == '0' || res[pos] == '.')
       {
           pos--;
       }
       res = res.substr(pos);
    }
    return res;
}
字符串明显\u格式\u尝试2(双d)
{
细流ss;
精密度(15);

ss你不能做你想做的事,因为十进制数不能用浮点格式精确表示。换句话说,
double
不能精确地保持
3.14
精确地说,它将所有东西都存储为2的幂分数,所以它存储为3+9175/65536左右(在你的计算器上这样做,你会得到3.1399993896484375。(我知道65536不是IEEE double的正确分母,但它的要点是正确的)

这就是所谓的往返问题。你不能这样做

double x = 3.14;
cout << magic << x;
double x=3.14;

cout准确格式化二进制浮点数非常棘手,而且传统上是错误的。1990年在同一杂志上发表的两篇论文确定,如果十进制值转换为二进制浮点数并返回,则可以恢复它们的值,前提是它们使用的十进制数字不超过特定的限制(C++中使用<代码> STD::数字限制::数字10<代码>适合的类型<代码> t>代码>:

  • Clinger’s描述了一种从十进制表示转换为二进制浮点的算法
  • Steele/White描述了如何将二进制浮点转换为十进制值。有趣的是,该算法甚至可以转换为最短的十进制值
在这些论文发表时,二进制浮点的C格式指令(
%f“
%e“
,和
%g”
)已经很好地建立起来了,并且考虑到新的结果,它们没有更改为。这些格式指令规范的问题是
%f”
假定在小数点后计算数字,并且没有格式说明符要求将数字格式化为特定数字,但不一定在小数点处开始计数(例如,使用小数点进行格式化,但可能有许多前导零)

<> >格式说明符仍然没有得到改善,例如,包括另一个可能包含许多零点的非科学符号,实际上,斯梯尔/白的算法的功率没有完全暴露。C++格式,在情况上没有改进,只是把语义委派给C格式的指导。侦探

不设置代码> STD::IOSKASE::固定< <代码>,使用精度>代码> STD::DigialIX限制:DigiS10/Cuth>是C和C++标准库提供的浮点格式的最接近近似值。使用“<代码> STD::IOSKBASE::SC”的格式可以获得请求的确切格式。科学的

,解析结果,然后重写数字。为了给这个过程提供一个漂亮的流式接口,可以用
std::num\u put
方面封装它

另一种方法是使用。此实现使用改进的(更快的)转换算法。它还公开了以某种形式获取数字的接口,但如果我回忆正确,则不会直接作为字符序列

我使用C++,我想用下面的明显方式格式化双打。 根据你的样品,我想你想要

  • 固定的而不是科学的符号
  • 合理(但不过度)的精度(这是为了用户显示,所以稍微四舍五入即可)
  • 尾随零被截断,并且
  • 如果数字看起来像整数,小数点也会被截断
以下函数仅用于此目的:

    #include <cmath>
    #include <iomanip>
    #include <sstream>
    #include <string>


    std::string fixed_precision_string (double num) {

        // Magic numbers
        static const int prec_limit = 14;       // Change to 15 if you wish
        static const double log10_fuzz = 1e-15; // In case log10 is slightly off
        static const char decimal_pt = '.';     // Better: use std::locale

        if (num == 0.0) {
            return "0";
        }

        std::string result;

        if (num < 0.0) {
            result = '-';
            num = -num;
        }

        int ndigs = int(std::log10(num) + log10_fuzz);
        std::stringstream ss;
        if (ndigs >= prec_limit) {
            ss << std::fixed
               << std::setprecision(0)
               << num;
            result += ss.str();
        }
        else {
            ss << std::fixed
               << std::setprecision(prec_limit-ndigs)
               << num;
            result += ss.str();
            auto last_non_zero = result.find_last_not_of('0');
            if (result[last_non_zero] == decimal_pt) {
                result.erase(last_non_zero); 
            }
            else if (last_non_zero+1 < result.length()) {
                result.erase(last_non_zero+1);
            }
        }
        return result;
    }
#包括
#包括
#包括
#包括
标准::字符串固定\u精度\u字符串(双数值){
//幻数
static const int prec_limit=14;//如果愿意,可以更改为15
static const double log10_fuzz=1e-15;//如果log10稍微关闭
静态常量char decimal_pt='.';//更好:使用std::locale
如果(num==0.0){
返回“0”;
}
std::字符串结果;
如果(数值<0.0){
结果='-';
num=-num;
}
int ndigs=int(std::log10(num)+log10_fuzz);
std::stringstream-ss;
如果(ndigs>=预测极限){

学生:你看了吗?请提供你正在使用的代码,并描述它不符合你的需要的方式。这可能是有趣的:我认为,但我不确定,你的目标是拥有尽可能短的十进制表示,当
操作符>>
读回时,它会给你内存中的原始值。这表明
3.14
3.140
都是一样的-你总是可以删除尾随的零。但这句话也解释了为什么可以删除非零数字。我编辑了我的问题,以澄清浮点错误是可以接受的。我的问题是格式,而不是精度。十进制值最多为
std::numeric\u limits::digits10(即
16
)可以
    #include <cmath>
    #include <iomanip>
    #include <sstream>
    #include <string>


    std::string fixed_precision_string (double num) {

        // Magic numbers
        static const int prec_limit = 14;       // Change to 15 if you wish
        static const double log10_fuzz = 1e-15; // In case log10 is slightly off
        static const char decimal_pt = '.';     // Better: use std::locale

        if (num == 0.0) {
            return "0";
        }

        std::string result;

        if (num < 0.0) {
            result = '-';
            num = -num;
        }

        int ndigs = int(std::log10(num) + log10_fuzz);
        std::stringstream ss;
        if (ndigs >= prec_limit) {
            ss << std::fixed
               << std::setprecision(0)
               << num;
            result += ss.str();
        }
        else {
            ss << std::fixed
               << std::setprecision(prec_limit-ndigs)
               << num;
            result += ss.str();
            auto last_non_zero = result.find_last_not_of('0');
            if (result[last_non_zero] == decimal_pt) {
                result.erase(last_non_zero); 
            }
            else if (last_non_zero+1 < result.length()) {
                result.erase(last_non_zero+1);
            }
        }
        return result;
    }