C++ 简洁准确的双精度印刷

C++ 简洁准确的双精度印刷,c++,printf,C++,Printf,我有一个double x,我想打印成字符串s。我希望表示符合以下属性: 准确:(x-atof(s))的绝对值小于ε 简明:表示法中包含的有效数字不超过准确所需的有效数字 最好的方法是什么 要说明为什么%f和%g不执行此任务,请执行以下操作: printf("%f\n", 1.0); // 1.000000 not concise printf("%g\n", 1.0); // 1 good printf

我有一个
double x
,我想打印成字符串
s
。我希望表示符合以下属性:

  • 准确
    (x-atof(s))
    的绝对值小于ε
  • 简明:表示法中包含的有效数字不超过准确所需的有效数字
最好的方法是什么

要说明为什么
%f
%g
不执行此任务,请执行以下操作:

printf("%f\n", 1.0);              // 1.000000       not concise
printf("%g\n", 1.0);              // 1              good
printf("%f\n", 4357890.2342389);  // 4357890.234239 good
printf("%g\n", 4357890.2342389);  // 4.35789e+06    not accurate

您可以配置格式说明符,如下所述:

既然你把这个标记为C++,为什么不试试这个:

#include <iostream>

std::cout << double(1.0) << std::endl
std::cout << 1.0 << std::endl
std::cout << double(4357890.2342389) << std::endl    
std::cout << 4357890.2342389 << std::endl
#包括
std::cout您可以使用as(提到的)格式说明符
%.16g
进行printf,或者使用
std::cout
进行类似操作:

#include <iostream>
#include <iomanip>

int main()
{
    std::cout << 4357890.2342389 << std::endl;

    std::cout << std::setprecision(16);

    std::cout << 4357890.2342389 << std::endl;
    std::cout << 1.0 << std::endl;

    std::cout << std::fixed;
    std::cout << "fixed\n";

    std::cout << 4357890.2342389 << std::endl;
}
在线代码

注意:您必须始终考虑浮点精度问题


推荐阅读:

为了满足您的要求,您可以做一些像这样丑陋的事情:

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

std::string concise_and_accurate( double x, int prec ) {
    // print the number to a stringstream with all the figures needed
    std::stringstream strnum;
    strnum << std::fixed << std::setprecision(prec) << x;
    std::string str = strnum.str();
    // cancel the extra zeroes at the right
    str.erase( str.find_last_not_of('0') + 1, std::string::npos );
    // delete the '.' if there are no other digits at the right
    if ( str[str.size()-1] == '.' ) str.erase(str.size()-1);
    return str; 
}


int main() {
    double test[] = { 4357890.2342389, 1.0, 1.0/3, 100.0/3 };

    for ( auto x : test ) {
        std::cout << concise_and_accurate(x,6) << '\n';
    }

    return 0;
}

%.16g
或者类似的东西?@cppleener很酷,效果很好。虽然
%.16g
对我上面的例子很有效,但从技术上讲,如果epsilon是,比如说1e-6,它就不能满足我对
1.0/3
的“简明”定义。这个解决方案很适合我的需要,但我想指出这一点,以防其他人有不同的需求。如果epsilon是1e-6,您对“
1.0/3
”的预期输出是什么?0.333333?@Bob_u_u_u_u是的。从技术上讲,没有其他字符串满足我的要求。将双精度值转换为双精度值的原因是什么?是否
iostream
printf
产生更好的结果?如果是,哪些方面得到了改进-是否更准确?更简洁?两者都是C++的方式去实现那些东西。结果应该大致相同,但不必提供格式说明符。如果更改数据类型,则流调用中不需要更新格式说明符。C++的浮点格式糟糕透顶。除非你指定固定的/科学的/随便什么,否则你完全是随心所欲。使用双掷,你会强制数字存储为双掷并通过流。我只是想说明这是另一种选择。正如我在OP的评论中所指出的,这个解决方案很好地满足了我的需要,但从技术上讲,如果epsilon是(比如)1e-6,它就不能满足我对
1.0/3
之类的“简明”定义。记下这一点,以防有人真的想要我在作品中精确列出的要求。这是一次英勇的努力!出于性能原因,我们的系统实际上使用printf样式的格式,字符串转换在单独的低优先级线程中完成。我最终可能会采用您的解决方案,使用自定义%格式化程序,但首先我需要解决这个问题,它已经在我们的待办事项列表上出现了一段时间。@dshin我一直认为
的全部目的是摆脱所有%格式化程序,并提供一个类型安全的缓冲IO。当然,这是有代价的。您是否测量过两种方法在性能上的差异,它们试图最小化写调用(少数cout使用大串接字符串)?是的,cout对于我们的性能要求来说太慢了。开箱即用的printf也会太慢,因为
printf(“非常长的格式字符串%d\n”,10)
的成本会随着格式字符串的长度而变化。我们的系统只是将格式字符串地址和参数一起复制到缓冲区。
4.35789e+06
4357890.2342389
1
fixed
4357890.2342389002442360
#include <iostream>
#include <iomanip>
#include <sstream>
#include <string>

std::string concise_and_accurate( double x, int prec ) {
    // print the number to a stringstream with all the figures needed
    std::stringstream strnum;
    strnum << std::fixed << std::setprecision(prec) << x;
    std::string str = strnum.str();
    // cancel the extra zeroes at the right
    str.erase( str.find_last_not_of('0') + 1, std::string::npos );
    // delete the '.' if there are no other digits at the right
    if ( str[str.size()-1] == '.' ) str.erase(str.size()-1);
    return str; 
}


int main() {
    double test[] = { 4357890.2342389, 1.0, 1.0/3, 100.0/3 };

    for ( auto x : test ) {
        std::cout << concise_and_accurate(x,6) << '\n';
    }

    return 0;
}
4357890.234239
1
0.333333
33.333333