快速扫描双c ++的方法

时间:2013-01-15 18:33:12

标签: c++ c performance double micro-optimization

我正在尝试优化我的问题解决方案,这需要快速双重扫描。我试图实现一个从标准输入中读取double的函数,但是我失败了。有人能指出一些简单的代码来有效地实现这一点吗?提前谢谢。

注意这是我的尝试,似乎有一些问题:

#include <stdio.h>
#include <stdlib.h>

inline double getDouble(FILE *f = stdin) {
    char tmp[20], ch;
    bool seen = false;
    double sign = 1.0;
    short index = 0;

    while((ch = getc(stdin)) != EOF) {
        if(ch == '-') {
            sign = -1.0;
            continue;
        }
        if(ch == ' ' || ch == '\n') {
            if(seen) break;
        } else {
            seen = true;
            tmp[index++] = ch;
        }
    }
    return sign * (double)atof(tmp);
}

int main() {
    int n;
    scanf("%d", &n);

    double *d = new double[n];

    for(int i=0; i<n; ++i) {
        d[i] = getDouble();
    }

    for(int i=0; i<n; ++i) {
        printf("%.5lf\n", d[i]);
    }

    return 0;
}

输入:

16
-2 -1 -4 -5
1 1 1 1
1.233 -435 -2.44
3
2 3 42 4 

2 个答案:

答案 0 :(得分:1)

#include <stdio.h>
#include <stdlib.h>

inline double getDouble(FILE *f = stdin) {
    double d;
    scanf("%lf", &d);
    return d;
}

int main() {
    int n;
    scanf("%d", &n);

    double *d = new double[n];

    for(int i=0; i<n; ++i) {
        d[i] = getDouble();
    }

    for(int i=0; i<n; ++i) {
        printf("%.5lf\n", d[i]);
    }

    return 0;
}

编辑:它确实可以更快一些,我估计以下是2到3倍的速度,它会通过你的输入,但需要相当多的假设,在测试样本之外没有保证:)

inline double getDouble(FILE *f = stdin) {
    char ch;
    bool seen = false;
    bool sign = false;
    char values[10];
    double result =0.;
    bool beforeDot = true;
    int beforeLength = 0;
    double multiplier;

    while((ch = getc(stdin)) != EOF) {
        if(ch == '-') {
            sign = true;
            continue;
        }
        if(ch == ' ' || ch == '\n') {
            if(seen) break;
            continue;
        }
        if(ch == '.') {
            beforeDot = false;
            multiplier = 1.;
            while(beforeLength) {
                result += (double)(values[--beforeLength] - '0') * multiplier;
                multiplier *= 10.;
            }
            multiplier = 10.;
        }
        else {
            if(!beforeDot)
            {
                result += double(ch - '0') / multiplier;
                multiplier *= 10.;
            } else {
                values[beforeLength++] = ch;
            }
            seen = true;
        }
    }
    if(beforeDot) {
        multiplier = 1;
        while(beforeLength) {
            result += (double)(values[--beforeLength] - '0') * multiplier;
            multiplier *= 10.;
        }
    }

    if(sign) result *= -1.;

    return result;
}

答案 1 :(得分:0)

我的第一个测试是:

inline double getDouble(std::istream& in = std::cin)
{
     double value;
     if (!(in >> value)) {throw "Error";}
     return value;
}

如果这还不够快(只有那时),我会尝试:

inline double getDouble(FILE *f = stdin)
{
    double value;
    if ((scanf(f, "%e", &value) != 1) { throw "Error";}
    return value;
}

如果这不够快(只有那时),我会尝试:
我怀疑这会比scanf()更快,因为人们有很多时间来优化它

inline double getDouble(FILE *f = stdin)
{
     int c;

     // Ignore leading white space
     while((c = getc(f) != EOF) && std::is_space(c)) {/*Loop*/}

     // Only dealing with reals that look like this:
     // [+|-]?[0-9]+(.[0-9]*)?
     // or
     // [+|-]?([0-9]*)?.[0-9]+

     // Deal with sign
     c=getc(f);
     char sign = 1;
     if ((c == '-') || (c == '+'))
     {
         if (c == '-') { sign = -1;}
         c=getc(f);
     }

     int  top
     int  bot;
     // See if next character is a '.'
     if (c == '.')
     {
         top = 0;
         bot = readDigits(f, c, true);
     }
     else
     {
         top = readDigits(f, c, true);
         bot = 0;
         if (c == '.')
         {
             c = getc(f);
             bot = readDigits(f, c, false);
         }
     }
     //put back the last unused character
     putc(c, f);

     // calculate the result.
     double result = sign * (top*1.0 + (bot*1.0/getSizeofBot(bot)));
     return result;
}
int readDigits(FILE* f, int& c, bool digitRequired)
{
     // c contains the first character.
     // It should contain the last character read on exit.

     // If digitRequired is true it is an exception to not 
     // find a digit, Other wise it is OK.
     if ((digitRequired) && !std::is_digit(c))
     {    throw "Error";
     }
     // Read an integer and return its value.
     int value = 0;

     while(std::is_digit(c))
     {
         value = value * 10 + (c - '0');
         c = getc(f);
     }
     return value;
}