Re[3]: Как проверить очень быстро...
От: Кодт Россия  
Дата: 06.01.02 13:01
Оценка: 12 (2)
Здравствуйте, all!

"Он не хочет умирать медленно и мучительно, он хочет — быстро и мучительно!"

Очень быстрый, но злой способ: конечный автомат на таблицах (7 состояний * 256 чар)
(char, state) --> newstate

Менее злой и быстрый: КА на проверках.

Грамматика числа выглядит так:
<floatnum> ::=
(start)       [ <sign> ]
(startint)    <digit>
(integral)    [{ <digit> }]
              [ <dot>
(fractional)    [{ <digit> }]
              ]
              [ <exp>
(startexp)      [ <sign> ]
(startpower)    <digit>
(power)         [{ <digit> }]
              ]
(end)

<sign> ::= + | -
<digit> ::= 0 .. 9
<dot> ::= .
<exp> ::= E | e

(в круглых скобках указаны названия состояний; см. код ниже)


Вот, например:
bool test(const char* str)
{
  enum STATE { s_start, s_startint, s_int, s_frac, s_startexp, s_startpower, s_power,
               s_total, s_error = -1, s_success = -2 };
  STATE state = s_start;

  while(state != s_error)
  {
    char chr = *(str++);

    if(chr == 0) // end of string
    {
      static const STATE next_eos[s_total] = {
        s_error, s_error, // incomplete mantissa
        s_success, s_success // complete mantissa
        s_error, s_error, // incomplete exp part
        s_success, // complete exp part
        };
      state = next_eos[state];
      return state == s_success;
    }

    if(chr == '+' || chr == '-') // sign
    {
      static const STATE next_sign[s_total] = {
        s_startint,
        s_error, s_error, s_error, // repeated sign within mantissa
        s_startpower,
        s_error, s_error, // repeated sign within exp
        };
      state = next_sign[state];
      continue;
    }

    if(chr == '.') // fraction point
    {
      static const STATE next_dot[s_total] = {
        s_error, s_error, // at least 1 digit should be in an integer part of mantissa
        s_frac,
        s_error, s_error, s_error, // unexpected positions of a dot
        };
      state = next_dot[state];
      continue;
    }

    if(chr == 'e' || chr == 'E') // exp mark
    {
      static const STATE next_exp[s_total] = {
        s_error, s_error, // incomplete mantissa
        s_startexp, s_startexp,
        s_error, s_error, s_error, // repeated exp mark
        };
      state = next_exp[state];
      continue;
    }

    if(chr >= '0' && chr <= '9')
    {
      const STATE next_digit[s_total] = {
        s_int, s_int, s_int, // begin/continue integral part
        s_frac, // begin/continue fractional part
        s_power, s_power, s_power, // begin/continue exp part
        };
      state = next_digit[s_total];
      continue;
    }

    // all other chars
    state = s_error;
    return false;
  }

  return state == s_success;
}


А на таблицах сие выглядит так

enum STATE { s_start, s_startint, s_int, s_frac, s_startexp, s_startpower, s_power,
             s_total, s_error, s_success };

static const next_eos[s_total], next_dot[s_total], ... ; // см. выше
static const next_error[s_total] = { s_error, s_error, s_error, s_error, s_error, s_error, s_error };

static STATE* next[256];

void initnext()
{
  int i;
  for(i = 0; i < 256; i++) next[i] = next_error;

  next[0] = next_eos;
  next['.'] = next_dot;
  // и т.д.
}

void test(const char* str)
{
  STATE state = s_start;
  while(state >= 0)
    state = next[(unsigned char)(*(str++))][state];
  return state == s_success;
}
Перекуём баги на фичи!
Как проверить очень быстро...
От: Holms США  
Дата: 06.12.01 07:33
Оценка:
является ли строка числом (целым, вещественным не имеет значения)?
The life is relative and reversible.
Re: Как проверить очень быстро...
От: Аноним  
Дата: 06.12.01 08:34
Оценка:
Здравствуйте Holms, Вы писали:

H>является ли строка числом (целым, вещественным не имеет значения)?

Посмотри help на функции atoi, atof и т.п...
Re: Как проверить очень быстро...
От: TSS Россия http://www.sdl.ru
Дата: 06.12.01 08:56
Оценка:
Здравствуйте Holms, Вы писали:

H>является ли строка числом (целым, вещественным не имеет значения)?

Имхо для ускорения имеет смысл не писать одну "универсальную" функцию для проверки всех чисел.

На целое десятичное проверяеться как:
  if (NULL == strpbrk (szString, "-+0123456789"))
  {
    // Не число !
    //
  }


Соттветственно для hex-ов "-+0123456789" меняется на "0123456789abcdefABCDEF", для действительных на "-+0123456789.eE", а дальше -- как душе угодно.
Signed, [TSS] /SDL/
Re[2]: Как проверить очень быстро...
От: Holms США  
Дата: 06.12.01 11:14
Оценка:
Здравствуйте TSS, Вы писали:

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


H>>является ли строка числом (целым, вещественным не имеет значения)?

TSS>Имхо для ускорения имеет смысл не писать одну "универсальную" функцию для проверки всех чисел.

TSS>На целое десятичное проверяеться как:

TSS>
TSS>  if (NULL == strpbrk (szString, "-+0123456789"))
TSS>  {
TSS>    // Не число !
TSS>    //
TSS>  }
TSS>


TSS>Соттветственно для hex-ов "-+0123456789" меняется на "0123456789abcdefABCDEF", для действительных на "-+0123456789.eE", а дальше -- как душе угодно.



Прогони пример посмотришь что получиться

int main(int argc, char* argv[])
{
    char *line = "123dsf,dfsdfz";
    if (NULL == strpbrk(line , "+-1234567890")) {
        printf("The string %s is not number", line);
    }else{
        printf("The string %s is number",line);
    }
    getch();
    return 0;
}
The life is relative and reversible.
Re: Как проверить очень быстро...
От: fAX Израиль  
Дата: 10.01.02 16:05
Оценка:
Здравствуйте Holms, Вы писали:

H>является ли строка числом (целым, вещественным не имеет значения)?


Народ, вы чего? вы б еще машину Тьюринга вспомнили.

По сути:
Если число целое (без знака):
очень быстро — делаешь logical OR (|) всех символов. Потом проверяешь или
if (result >= 0x30 && result <= 0x39)

можно проверять и в цикле, где делаешь OR. Но непонятно что быстрее будет ( на коротких строках)

Первое, что пришло в голову
...Complex problems have simple, easy-to-understand wrong answers...
(Grossman's Misquote of H.L.Mencken)
Re[2]: Как проверить очень быстро...
От: Кодт Россия  
Дата: 10.01.02 16:31
Оценка:
Здравствуйте fAX, Вы писали:

H>>является ли строка числом (целым, вещественным не имеет значения)?


fAX>Народ, вы чего? вы б еще машину Тьюринга вспомнили.


fAX>По сути:

fAX>Если число целое (без знака):
fAX>очень быстро — делаешь logical OR (|) всех символов. Потом проверяешь или
fAX>
fAX>if (result >= 0x30 && result <= 0x39)
fAX>

fAX>можно проверять и в цикле, где делаешь OR. Но непонятно что быстрее будет ( на коротких строках)

fAX>Первое, что пришло в голову


Ага, счаз!

"69" == 0x36 | 0x39 == 0x3F == "?"
"!0" == 0x21 | 0x30 == 0x31 == "1" == "!\x010" == 0x21 | 0x10

"123 4 5 6" == "123456" (" " --> 0x20)


Так что, все же, конечные автоматы...
Перекуём баги на фичи!
Re[3]: Как проверить очень быстро...
От: fAX Израиль  
Дата: 10.01.02 16:52
Оценка:
Здравствуйте Кодт, Вы писали:

К>Ага, счаз!


К>
К>"69" == 0x36 | 0x39 == 0x3F == "?"
К>"!0" == 0x21 | 0x30 == 0x31 == "1" == "!\x010" == 0x21 | 0x10
da, etot kamen` v ogorod prinimaju

К>"123 4 5 6" == "123456" (" " --> 0x20)
a tut vy, baten`ka pogorjachilis`.
К>


К>Так что, все же, конечные автоматы...

A kakaja byla ideja ... Pust` budut avtomaty...
...Complex problems have simple, easy-to-understand wrong answers...
(Grossman's Misquote of H.L.Mencken)
Re[4]: Как проверить очень быстро...
От: fAX Израиль  
Дата: 10.01.02 16:59
Оценка:
Sorry po vsem punktam....
...Complex problems have simple, easy-to-understand wrong answers...
(Grossman's Misquote of H.L.Mencken)
 
Подождите ...
Wait...
Пока на собственное сообщение не было ответов, его можно удалить.