문제

I'm trying to optimize my solution to a problem, which requires fast double scanning. I tried to implement a function which read a double from the standard input, but I failed. Could someone point me some simple code which implements this efficiently? Thanks in advance.

Note here is my attempt, which seems to have some problems:

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

Input:

16
-2 -1 -4 -5
1 1 1 1
1.233 -435 -2.44
3
2 3 42 4 
도움이 되었습니까?

해결책

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

Edit: It can indeed be some faster as this, I estimate the following to be 2 to 3 times as fast, it will pass your input, but takes quite some assumptions, no guarantees outside the test sample :)

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;
}

다른 팁

My first test would be:

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

If this is not fast enough (and only then) I would try:

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

If this is not fast enough (and only then) I would try:
And I doubt this would be faster than scanf() as people have had a lot of time to optimize it

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;
}
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top