常用功能可精确打印浮点数 [英] Commonly available functions for accurate floating-point number printing

查看:49
本文介绍了常用功能可精确打印浮点数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

弗洛里安·洛伊奇(Florian Loitsch)的精彩作品叫做使用整数快速而准确地打印浮点数" .在将任何类型的double打印为字符串的情况下,这听起来很有用.我认为很多人直到最近才知道我的信息,例如使用 setprecisiton(n) printf(%0.nf")设置修复精度,并且经常选择 n 太大而导致浮点数不精确,或者太小而无法截取有价值的数据.我想知道C ++标准(包括即将发布的),boost,libc或易于访问和测试的地方是否有与此类似的东西?

There is wonderful work of Florian Loitsch called "Printing Floating-Point Numbers Quickly and Accurately with Integers". This sounds pretty useful in case of printing any kind of double into string. I think many people included me until recently only know like setting a fix precision with setprecisiton(n) or printf("%0.nf") and often either choosing n too large and getting floating point imprecision or too small and cutting off valuable data. I wonder is there something similar to this in C++ standard (including upcoming), boost, libc, or somewhere easily reachable and tested?

推荐答案

我认为标准C ++库中没有任何真正好的解决方案.

I don't think there is any really good solution in the standard C++ library.

我使用一种技巧来尝试几种不同的格式,然后选择最短的文本表示形式,并且该文本表示形式在往返时具有完全相同的值.我用来保存在文本文件(XML)输出中的内容.

I use the trick of trying several different formats, and then selecting the text representation that is the shortest and the text representation has the exact same value when round-tripped. Which I use to save in my text file (XML) output.

有时这意味着选择严格的十六进制浮点表示形式.(可能会破坏您的用例.)

Which sometimes means selecting the exacting hexadecimal floating point representation. (May be a deal breaker for your use case.)

这是代码,我添加了一个表格以生成一些示例,如果最短,则将它们标记为 * ,如果是最短的标记,则使用 warning 标记他们不会往返.

Here's the code, which I've added a table to generate some examples, and mark them as * if they are the shortest, or with a warning marker if they do not round trip.

#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();
}

这篇关于常用功能可精确打印浮点数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆