c++字符串流太慢,如何加快

c++ stringstream is too slow, how to speed up?

本文关键字:何加快 字符串 c++      更新时间:2023-10-16

可能重复:
在C++中从文本文件读取数值的最快方法(在这种情况下是双倍的(

#include <ctime>
#include <cstdlib>
#include <string>
#include <sstream>
#include <iostream>
#include <limits>
using namespace std;
static const double NAN_D = numeric_limits<double>::quiet_NaN();
void die(const char *msg, const char *info)
{
    cerr << "** error: " << msg << " "" << info << '"';
    exit(1);
}
double str2dou1(const string &str)
{
    if (str.empty() || str[0]=='?') return NAN_D;
    const char *c_str = str.c_str();
    char *err;
    double x = strtod(c_str, &err);
    if (*err != 0) die("unrecognized numeric data", c_str);
    return x;
}
static istringstream string_to_type_stream;
double str2dou2(const string &str)
{
    if (str.empty() || str[0]=='?') return NAN_D;
    string_to_type_stream.clear();
    string_to_type_stream.str(str);
    double x = 0.0;
    if ((string_to_type_stream >> x).fail())
        die("unrecognized numeric data", str.c_str());
    return x;
}
int main()
{
    string str("12345.6789");
    clock_t tStart, tEnd;
    cout << "strtod: ";
    tStart=clock();
    for (int i=0; i<1000000; ++i)
        double x = str2dou1(str);
    tEnd=clock();
    cout << tEnd-tStart << endl;
    cout << "sstream: ";
    tStart=clock();
    for (int i=0; i<1000000; ++i)
        double x = str2dou2(str);
    tEnd=clock();
    cout << tEnd-tStart << endl;
    return 0;
}

strtod:405
sstream:1389

更新:删除undersocres,env:win7+vc10

C/C++文本到数字的格式化非常缓慢。流非常慢,但即使是C数解析也很慢,因为很难将其更正到最后一个精度位。

在一个阅读速度很重要的生产应用程序中,已知数据最多有三个十进制数字,没有科学的符号,我通过手工编码一个只处理符号、整数部分和任何小数位数的浮动解析函数(我所说的"巨大"指的是与strtod相比快10倍(,得到了巨大的改进。

如果你不需要指数,并且这个函数的精度足够,这是一个类似于我当时写的解析器的代码。在我的电脑上,它现在比strtod快6.8倍,比sstream快22.6倍。

double parseFloat(const std::string& input)
{
    const char *p = input.c_str();
    if (!*p || *p == '?')
        return NAN_D;
    int s = 1;
    while (*p == ' ') p++;
    if (*p == '-') {
        s = -1; p++;
    }
    double acc = 0;
    while (*p >= '0' && *p <= '9')
        acc = acc * 10 + *p++ - '0';
    if (*p == '.') {
        double k = 0.1;
        p++;
        while (*p >= '0' && *p <= '9') {
            acc += (*p++ - '0') * k;
            k *= 0.1;
        }
    }
    if (*p) die("Invalid numeric format");
    return s * acc;
}

字符串流慢。非常慢。如果您正在编写任何对大型数据集起作用的性能关键内容(比如在游戏中级别更改后加载资产(,请不要使用字符串流。我建议使用老式的c库解析函数来提高性能,尽管我不能说它们与boost spirit之类的函数相比如何。

然而,与c库函数相比,字符串流非常优雅、可读且可靠,因此如果您所做的不是性能循环,我建议您坚持使用流。

通常,如果您需要速度,可以考虑这个库:

http://www.fastformat.org/

(不过,我不确定它是否包含将字符串或流转换为其他类型的函数,所以它可能不符合您当前的示例(。

为了记录在案,请注意你在这里把苹果比作桔子。strtod()是一个简单的函数,具有单一的目的(将字符串转换为双精度(,而字符串流是一种复杂得多的格式化机制,远未针对特定目的进行优化。更公平的比较是将字符串流与函数的sprintf/scanf行进行比较,后者比strtod()慢,但仍然比字符串流快。我不太确定是什么让stringstream的设计比sprintf/scanf慢,但事实似乎就是这样。

您是否考虑过使用boost中的lexical_cast

http://www.boost.org/doc/libs/1_46_1/libs/conversion/lexical_cast.htm

编辑:顺便说一句,clear()应该是多余的。