Здравствуйте, 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;
}