2011-04-29 19 views
18

Duplicar posible:
Fastest way to read numerical values from text file in C++ (double in this case)C++ cadena de flujo es demasiado lento, ¿cómo acelerar?

#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 actualización

: eliminar undersocres, env: win7 + VC10

+0

Intente utilizar boost :: spirit en lugar de. – W55tKQbuRu28Q4xv

+1

Esos nombres de doble subrayado son ilegales en el código escrito por el usuario. y si las cadenas de caracteres son demasiado lentas para usted - usted tiene la respuesta - use strtod. las cadenas de caracteres están principalmente allí por conveniencia y tipo de seguridad, no de velocidad. –

+0

La transmisión recogerá la entrada y luego llamará a strtold para la conversión. ¡Hace difícil ser más rápido! –

Respuesta

1

Hav ¿Consideró usar lexical_cast de boost?

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

Editar: por cierto, la clear() debe ser redundante.

+0

gracias, pero creo que STL no está diseñado para ser lento – hjbreg

+1

+1 para 'lexical_cast' pero dado que es usando una secuencia de cuerda debajo, no será más rápido. –

+0

http://translate.google.com/translate?js=n&prev=_t&hl=en&ie=UTF-8&layout=2&eotf=1&sl=auto&tl=en&u=http%3A%2F%2Fsergey-miryanov.blogspot.com%2F2008%2F06 % 2Fblog-post.html – W55tKQbuRu28Q4xv

2

En general, si usted necesita velocidad, considere esta biblioteca:

http://www.fastformat.org/

(No estoy seguro de si contiene funciones para convertir cadenas o secuencias de otros tipos, sin embargo, lo que no puede responde tu ejemplo actual).

Para el registro, tenga en cuenta que está comparando manzanas con naranjas aquí. strtod() es una función simple que tiene un único propósito (convertir cadenas al doble), mientras que stringstream es un mecanismo de formateo mucho más complejo, que está lejos de ser optimizado para ese propósito específico. Una comparación más justa sería comparar stringstream a la línea de funciones sprintf/sscanf, que sería más lenta que strtod() pero aún más rápida que stringstream. No estoy exactamente seguro de qué hace que el diseño de stringstream sea más lento que sprintf/sscanf, pero parece que ese es el caso.

+0

por qué STL es más lento que formato rápido – hjbreg

+5

@hjbreg, porque tiene que admitir configuraciones regionales. –

+0

@hjbreg: hay varias razones para eso. Parte de esto puede estar relacionado con consideraciones de diseño de flujos e implementación no optimizada. Otra razón es la flexibilidad de STL, que probablemente incluye soporte local y soporte para manipuladores de IO (no estoy seguro si formato rápido tiene estos o algo equivalente). –

3

secuencia de cadenas es lento. Muy lento Si está escribiendo algo sobre el rendimiento crítico que actúa en grandes conjuntos de datos (por ejemplo, carga de activos después de un cambio de nivel durante un juego), no use cadenas de transmisión. Recomiendo usar las funciones de análisis de biblioteca de la vieja escuela c para el rendimiento, aunque no puedo decir cómo se comparan con algo así como impulsar el espíritu.

Sin embargo, en comparación con las funciones de la biblioteca c, las secuencias de cadenas son muy elegantes, legibles y fiables, por lo que si lo que está haciendo no es ciritcal, le recomiendo que se adhiera a las transmisiones.

8

El formato de texto a formato C/C++ es muy lento. Las transmisiones son terriblemente lentas, pero incluso el análisis del número C es lento porque es bastante difícil corregirlo hasta el último bit de precisión.

En una aplicación de producción donde la velocidad de lectura era importante y donde los datos tenían un máximo de tres dígitos decimales y ninguna notación científica obtuve una gran mejora al codificar manualmente una función de análisis flotante que solo manejaba signo, parte entera y cualquier número de decimales (por "vasto" quiero decir 10 veces más rápido en comparación con strtod).

Si no necesita exponente y la precisión de esta función es suficiente, este es el código de un analizador similar al que escribí en ese momento. En mi PC ahora es 6.8 veces más rápido que strtod y 22.6 veces más rápido que sstream.

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