Re[4]: Вообще не понимаю, о чем разговор...
От: Kluev  
Дата: 17.06.08 11:52
Оценка:
Здравствуйте, degor, Вы писали:

D>Здравствуйте, Kluev, Вы писали:


K>>Здравствуйте, degor, Вы писали:


D>вот тебе use case: "-.A". мегавелосипед возвращает num_parse_ok,а должен возвращать num_parse_syntax.

этот use case не встречается там где он используется, хотя я не отрицаю, что это ошибка.

D>но давайте будем честными перед собой, strtod() делает гораздо больше работы, чем твой велосипед. он использует локаль, проверяет специальные случаи, да и strlen() ему приходится делать в каждом цикле, а ты делаешь это только раз. и что-то я сомневаюсь, что гигабайты данных состоят сплошь из строк одного размера.


D>и о методике. возьми чиселки подлиннее, например, символов из 30, и увидишь, что преимущество велосипеда над crt уже не столь велико.

к скорости strtod у меня нет претензий. неюзабельной ее делает strlen из-за которого невозможно парзить текст большими кусками.
так же я померял на больших строках разница в 2.5 раза получается.

вот обновленный универсальный велосипед для ascii-unicode-iterator и работающий как с диапазонами строк так и с сишными строками.
errcode = parse_real(value, str_begin, RangeTerm<const char*>(str_end));
errcode = parse_real(value, str, ZeroTerm());



#pragma once

#include <float.h>

//==================================================================
template <class T>
    class NumberTraits;

//==================================================================
template <>
    class NumberTraits<double>
{
public:
    static int
        is_finite(double v)
    {
        return _finite(v);
    }
};

//==================================================================
template <class Iter>
struct RangeTerm
{
    Iter    end;

    RangeTerm(Iter e)
        : end (e)
    {
    }

    bool operator ()(Iter it)
    {
        return it == end;
    }
};

struct ZeroTerm
{
    template <class Iter>
        bool operator ()(Iter it)
    {
        return 0 == *it;
    }
};

enum
{
    NUM_PARSE_OK = 0,
    NUM_PARSE_EOF,
    NUM_PARSE_SYNTAX,
    NUM_PARSE_OVERFLOW,
};

template <class V, class Iter, class Term> int
    parse_real(V &res, Iter &p, Term eof)
{
    typedef NumberTraits<V> NT;

    V val       = 0;
    V sign      = 1;
    int esign   = 1;
    V ep;
    int    fdigits = 0;        
    bool has_ip = false;
    bool has_fp = false;

// skip space chars
    while (!eof(p))
    {
        if (' ' == *p || (*p > 0x8 && *p < 0xE))
            ++p;
        else
            goto space_ok;
    }
// eof here
    return NUM_PARSE_EOF;

space_ok: // +-.digit
    if (*p >= '0' && *p <= '9')
        goto ip_parse;

    if ('-' == *p)
        { sign = -1; goto sign_ok; }
    if ('+' == *p)
        goto sign_ok;

    if ('.' == *p)
        goto dot_ok;

    return NUM_PARSE_SYNTAX;

sign_ok: // .digit
    if (eof(++p))
        return NUM_PARSE_EOF;

    if (*p >= '0' && *p <= '9')
        goto ip_parse;

    if ('.' == *p)
        goto dot_ok;

    return NUM_PARSE_SYNTAX;

ip_parse:
    has_ip = true;
    val    = *p - '0';
    ++p;
    while(!eof(p))
    {
        if (*p >= '0' && *p <= '9')
        {
            val = val*10 + *p - '0';
            ++p;
        }
        else
            goto ip_ok;
    }
// eof here
    res = val*sign;
    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;

ip_ok: //.eEdD
    if ('.' == *p)
        goto dot_ok;

    if ('e' == *p || 'E' == *p || 'd' == *p || 'D' == *p)
        goto ep_ok;

    if (!has_ip)
        return NUM_PARSE_SYNTAX;
    res = val*sign;
    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;

dot_ok: // digit or eEdD
    if (eof(++p))
    {
        if (!has_ip)
            return NUM_PARSE_SYNTAX;
        res = val*sign;
        return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;
    }

    if (*p >= '0' && *p <= '9')
        goto fp_parse;

    if ('e' == *p || 'E' == *p || 'd' == *p || 'D' == *p)
        goto ep_ok;

    if (!has_ip)
        return NUM_PARSE_SYNTAX;
    res = val*sign;
    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;

fp_parse:
    val     = val*10 + *p - '0';
    fdigits = 1;
    has_fp  = true;
    ++p;

    while(!eof(p))
    {
        if (*p >= '0' && *p <= '9')
        {
            val = val*10 + *p - '0';
            ++fdigits;
            ++p;
        }
        else
            goto fp_ok;
    }
// eof here
    res = sign*val*pow(10.,-fdigits);
    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;

fp_ok: // eEdD
    if ('e' == *p || 'E' == *p || 'd' == *p || 'D' == *p)
        goto ep_ok;

    if (!(has_ip || has_fp))
        return NUM_PARSE_SYNTAX;
    res = sign*val*pow(10.,-fdigits);
    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;

ep_ok: //+-digit
    if (eof(++p))
    {
        if (!(has_ip || has_fp))
            return NUM_PARSE_SYNTAX;
        res = sign*val*pow(10.,-fdigits);
        return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;
    }

    if (*p >= '0' && *p <= '9')
        goto ep_parse;

    if ('-' == *p)
        { esign = -1; goto esign_ok; }

    if ('+' == *p)
        goto esign_ok;

    return NUM_PARSE_SYNTAX;

esign_ok:
    if (eof(++p))
        return NUM_PARSE_SYNTAX;

    if (*p >= '0' && *p <= '9')
        goto ep_parse;

    return NUM_PARSE_SYNTAX;

ep_parse:
    ep = *p - '0';
    ++p;
    while (!eof(p))
    {
        if (*p >= '0' && *p <= '9')
        {
            ep = ep*10 + *p - '0';
            ++p;
        }
        else
            break;
    }

    if (ep > 1e6)
    {
        ep *= esign;
        ep -= fdigits;
        res = sign*val*pow(10., ep);
    }
    else
    {
        int iep = esign*int(ep)-fdigits;
        res = sign*val*pow(10., iep);
    }

    return NT::is_finite(res) ? NUM_PARSE_OK : NUM_PARSE_OVERFLOW;
}
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.