C++ 用于精确浮点数字打印的常用函数
弗洛里安·洛伊奇有一个很棒的作品叫做。在将任何类型的双精度字符打印到字符串中时,这听起来非常有用。我想包括我在内的许多人直到最近都只知道像使用C++ 用于精确浮点数字打印的常用函数,c++,floating-point,C++,Floating Point,弗洛里安·洛伊奇有一个很棒的作品叫做。在将任何类型的双精度字符打印到字符串中时,这听起来非常有用。我想包括我在内的许多人直到最近都只知道像使用setprecisionon(n)或printf(“%0.nf”)设置固定精度,并且经常选择n太大而得到浮点不精确,或者太小而切断有价值的数据。在C++标准(包括即将到来的)、Boost、LIBC或某个容易到达和测试的地方,我想知道类似的事情吗? 用于精确浮点数字打印的常用函数 Post最初标记为[C]和[C++] // Hexadecimal/deci
setprecisionon(n)
或printf(“%0.nf”)
设置固定精度,并且经常选择n
太大而得到浮点不精确,或者太小而切断有价值的数据。在C++标准(包括即将到来的)、Boost、LIBC或某个容易到达和测试的地方,我想知道类似的事情吗?
用于精确浮点数字打印的常用函数
Post最初标记为[C]和[C++]
// Hexadecimal/decimal exponential output.
printf("%a\n", value);
// Decimal exponential output with sufficient precision to distinguish against other double
printf("%.*e\n", DBL_DECIMAL_DIG - 1, double_value);
// Decimal sometimes exponential output with sufficient precision to distinguish against other double
printf("%.*g\n", DBL_DECIMAL_DIG, double_value);
所有有限浮点值都是精确的。很少有人需要把它精确地看作小数点。这是. 我认为在标准C++库中没有任何真正好的解决方案。 我使用的技巧是尝试几种不同的格式,然后选择最短的文本表示法,当往返时,文本表示法具有完全相同的值。我用它保存在我的文本文件(XML)输出中 这有时意味着选择精确的十六进制浮点表示。(可能是您用例的交易破坏者。) 下面是代码,我添加了一个表来生成一些示例,如果它们是最短的,则将它们标记为
*
,如果它们不是往返的,则使用警告标记
#include <iomanip>
#include <ios>
#include <iostream>
#include <sstream>
using std::cout;
using std::defaultfloat;
using std::fixed;
using std::hexfloat;
using std::istringstream;
using std::left;
using std::scientific;
using std::setw;
using std::string;
using std::stringstream;
enum class cap { title, middle, end };
static void print(const char* text, double num, cap c) {
stringstream ss;
ss << fixed << num;
auto s = ss.str();
double fn = stod(s);
size_t flen = s.length();
string falert = "";
if (fn != num) { falert = "/!\\"; flen += 100; }
ss.str("");
ss.clear();
ss << scientific << num;
s = ss.str();
double sn = stod(s);
size_t slen = s.length();
string salert = "";
if (sn != num) { salert = "/!\\"; slen += 100; }
ss.str("");
ss.clear();
ss << hexfloat << num;
s = ss.str();
double hn = stod(s);
size_t hlen = s.length();
string halert = "";
if (hn != num) { halert = "/!\\"; hlen += 100; }
ss.str("");
ss.clear();
ss << defaultfloat << num;
s = ss.str();
double dn = stod(s);
size_t dlen = s.length();
string dalert = "";
if (dn != num) { dalert = "/!\\"; dlen += 100; }
char gbuf[256];
sprintf(gbuf, "%g", num);
s = gbuf;
double gn = stod(s);
size_t glen = s.length();
string galert = "";
if (gn != num) { galert = "/!\\"; glen += 100; }
if (flen <= slen && flen <= hlen && flen <= dlen) falert += "*";
if (slen <= flen && slen <= hlen && slen <= dlen) salert += "*";
if (hlen <= flen && hlen <= slen && hlen <= dlen) halert += "*";
if (dlen <= flen && dlen <= hlen && dlen <= slen) dalert += "*";
if (glen <= dlen && glen <= flen && glen <= hlen && glen <= slen) galert += "*";
if (c == cap::title) cout <<
"┌──────────┬────────────┬──────────────────────────┐\n"
"│ number │ iomanip │ representation │\n"
"├──────────┼────────────┼──────────────────────────┤\n"
;
cout << left
<< "│ " << setw(8) << text << " │ fixed │ " << setw(24) << fixed << num << " │" << falert << "\n"
<< "│ " << setw(8) << text << " │ scientific │ " << setw(24) << scientific << num << " │" << salert << "\n"
<< "│ " << setw(8) << text << " │ hexfloat │ " << setw(24) << hexfloat << num << " │" << halert << "\n"
<< "│ " << setw(8) << text << " │ default │ " << setw(24) << defaultfloat << num << " │" << dalert << "\n"
<< "│ " << setw(8) << text << " │ %g │ " << setw(24) << gbuf << " │" << galert << "\n"
;
cout << (c != cap::end ?
"├──────────┼────────────┼──────────────────────────┤\n" :
"└──────────┴────────────┴──────────────────────────┘\n" );
}
static void table() {
print("0.0", 0.0, cap::title);
print("0.01", 0.01, cap::middle);
print("0.00001", 0.00001, cap::middle);
print("1e99" , 1.e+99, cap::middle);
print("0.1" , 0.1, cap::middle);
print("0.2" , 0.2, cap::middle);
print("0.3" , 0.3, cap::middle);
print("0.4" , 0.4, cap::middle);
print("0.5" , 0.5, cap::middle);
print("0.6" , 0.6, cap::middle);
print("0.7" , 0.7, cap::middle);
print("0.8" , 0.8, cap::middle);
print("0.9" , 0.9, cap::middle);
print("NTSC" , 30.0/1001.0, cap::middle);
print("1/3" , 1.0/3.0, cap::end);
}
int main() {
table();
}
#包括
#包括
#包括
#包括
使用std::cout;
使用std::defaultfloat;
使用std::fixed;
使用std::hexfloat;
使用std::istringstream;
使用std::left;
使用std::scientific;
使用std::setw;
使用std::string;
使用std::stringstream;
枚举类cap{title,middle,end};
静态无效打印(常量字符*文本,双数字,大写c){
细流ss;
在阅读PDF之前先阅读ss:printf(“%g”,value)使用默认精度6,即,你必须指定精度。这能回答你的问题吗?C和C++是不同的语言,同时产生不同的答案。我已经删除了C标签,因为这个问题特别提到C++标准,因此似乎是针对C++的。“正确的打印成为许多语言规范的一部分,而且所有主要的C库(以及所有依赖于printf
函数的程序)现在都采用了准确的算法并打印正确的结果。”OP可能需要生成唯一的数字数的算法,这些数字需要唯一地标识转换的特定数字的原始值。C++库例程不这样做,即使它们正确地循环(标准不需要,除非它已经升级)。@EricPostpischil使用非OP编辑的语言标记,这个C答案可能仍然会为OP带来一些启示。至于OP真正想要什么,如果它不是“用于精确浮点数字打印的常用功能”也可能会演变。@chux谢谢。但这不起作用,它不能准确地表示数字。例如,100.74
使用这种方法会以单精度错误地表示。@Yuki当然这是一个内部表示的问题。大多数十进制分数只能用二进制分数近似,这就是有限精度IEEE-754二进制浮点数的含义。这似乎是“浮点数学坏了吗?”@njuffa我不认为数学坏了。我知道浮点内部工作的一些基本原理。你可以试着阅读这篇论文的乞求,以了解我所说的内容。