在C++中从文本文件中读取数值的最快方法(在这种情况下为double)

Sim*_*mon 15 c++

目前,我的代码就是这样:

void ReadFile(double Cst[][1000], char* FileName, int height)

FILE* ifp;
double value;
int nRead = 0;
int mRead = 0;

//open the file, check if successful
ifp = fopen( FileName, "r" );
if (ifp==NULL){
    ...
}


for (nRead = 0; nRead < height; nRead++){
    for (mRead = 0; mRead < 1000; mRead++){
        fscanf(ifp, "%le",&value);
        Cst[nRead][mRead]=value;
    }
}

fclose(ifp);
Run Code Online (Sandbox Code Playgroud)

我可以改变什么来使它尽可能快?

ild*_*arn 17

提升.精神.QI带有一个基准来比较的性能std::atof,std::strtodboost::spirit::qi::double_.以下是我的系统上的结果,使用VC++ 2010 SP1 x64和Boost 1.46.1:

atof_test:4.1579秒
strtod_test:4.2339秒
spirit_qi_double_test:1.2822秒

这使得Spirit.QI 比下一个最快的可验证*选项快230%,比下一个最快的无法验证的选项快224% - 相当快,我会说!

*与之不同std::atof,std::strtodBoost.Spirit会告诉您输入是否有效.


更新:我再次使用Boost重新运行基准测试.精神.X3boost::spirit::x3::double_; 以下是我目前系统的结果,使用VC++ 2015 Update 3 x64和Boost 1.61.0:

atof_test:2.2874秒
strtod_test:2.2923秒
spirit_qi_double_test:0.4849秒
spirit_x3_double_test:0.4308秒

这使得Spirit.QI比下一个最快的可验证选项快373%,比下一个最快的无法验证的选项快372%,而Spirit.X3 比下一个最快的可验证选项快432%,比下一个最快的无法验证选项快431% - 对于Spirit来说,事情已经有了显着改善,而且最重要的是,基于X3的代码在大约1/3的时间内编译为基于QI的代码,所以在那里也能获胜!

此外,我已经在基准代码@ Potatoswatter的答案(改性双精度指数表,并支持负数(代码)),@ 6502的答案,并@迈赫达德的回答,用相同的构建和测试环境.以下是结果(@ 6502的代码被排除,因为我的样本输入的一半使用科学记数法,他的代码不支持):

potatoswatter_test:0.2358秒
mehrdad_test:0.3415秒

如果所有输入都转换为固定表示法,我们也可以测试@ 6502的代码:

atof_test:3.6249秒
strtod_test:3.7023秒
spirit_qi_double_test:1.0763秒
spirit_x3_double_test:2.3657秒
potatoswatter_test:0.8347秒
6502_test:4.1463秒
mehrdad_test:1.3471秒

值得注意的是,QI无法解析一些非常长的固定符号输入; X3正确地解析了这些,但运行速度明显慢于科学符号输入短.

  • 当然,像所有提升精神一样,基准测试没有考虑编译时间:)我的建议是将其存储在特定的源文件中,以限制重新编译的时间:) (4认同)

Pot*_*ter 13

举个例子,这是我的一个项目中一个非常快速的数字解析器.它只处理标准库数值解析的实际功能的一小部分.

uint64_t mystrtol( char *&pen, uint64_t val = 0 ) {
    for ( char c; ( c = *pen ^ '0' ) <= 9; ++ pen ) val = val * 10 + c;
    return val;
}

value_t mystrtof( char *&pen ) {
    static value_t const exp_table[]
     = { 1e5, 1e4, 1e3, 1e2, 10, 1, 0.1, 1e-2, 1e-3, 1e-4, 1e-5, 1e-6, 1e-7, 1e-8, 1e-9, 1e-10, 1e-11, 1e-12, 1e-13, 1e-14, 1e-15, 1e-16, 1e-17 },
     * exp_lookup = & exp_table[ 5 ];

    while ( iswspace( * ++ pen ) ) ;
    //if ( *pen == '-' ) ++ pen; // don't think we ever care about negative numbers
    uint64_t val = mystrtol( pen );
    int neg_exp = 0;
    if ( *pen == '.' ) { // mainly happens when val = 0
        char const *fracs = ++ pen;
        val = mystrtol( pen, val );
        neg_exp = pen - fracs;
    }
    if ( ( *pen | ('E'^'e') ) == 'e' ) {
        neg_exp += *++pen == '-'? mystrtol( ++ pen ) : - mystrtol( ++ pen );
    }
    return val * exp_lookup[ neg_exp ];
}
Run Code Online (Sandbox Code Playgroud)


650*_*502 8

C/C++解析文本中的数字非常慢.流速非常慢,但即使是C数字解析也很慢,因为很难将其校正到最后一个精度位.

在一个生产应用程序中,读取速度很重要,并且已知数据最多有三个十进制数字且没有科学记数法,我通过手工编写浮点解析函数只得到符号,整数部分和任意数量的小数来获得了巨大的改进(通过"浩瀚",我的意思是相比,快10倍strtod.

如果你不需要exponent并且这个函数的精度足够,那么这就是我所写的解析器的代码.在我的电脑上,它现在比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;
}
Run Code Online (Sandbox Code Playgroud)


Ben*_*igt 6

atof 可能要快得多,它不必处理格式字符串.

如果您不需要支持所有1001个已识别的输入格式(使用和不使用指数等),那么自定义函数可能会更快.如果atof对你来说仍然太慢,那么我可以清理我使用的代码(目前不适合公开发布).


我只记得这个问题atof- 它没有告诉你数字在哪里结束,所以很难按顺序读取几个数字. strtod在这方面更好.