2016-09-23 2 views
0

현재 아래 코드가 있습니다. 그러나 3.1 ~ 43과 같은 항목이 입력 된 경우에는 여전히 float로 표시됩니다. 나는 내가 잘 지키지 않았 음을 안다. 그러나 나는 그것을 확인하는 방법을 확신하지 못한다.main에서 문자열이 유효한 float인지 확인하십시오.

int floatNum(char *s) { 
    char *ptr = s; 
    char *ep = NULL; 
    long i = strtol(s, &ep, 0); 

    //check if converted to long int 
    if (!*ep) { 
     return false; 
    } 

    //Check if char 
    if (*ep == 'e' || *ep == 'E' || *ep == '.') { 
     return true; 
    } 

    return false; 
} 

내 솔루션이 있습니다. 때문에 내 프로젝트가 설정되어 있기 때문에 나는 단지 유효 float 또는 그렇지 않으면 false를 반환하는 것이 좋습니다.

int floatNum(char *s) { 
    const char *ptr = s; 
    double x = strtod(ptr, &s); 

    //check if converted to long int 
    if (*s == 0) { 
     return true; 
    } 
    else { 
     return false; 
    } 
    return false; 
} 
+5

아마도 'strtod'를 사용해야합니다. – keltar

+0

@keltar 제안에 감사드립니다. – terribleProgrammer

+0

@terribleProgrammer 게시물을 변경하는 것보다 답변을 답으로 게시하는 것이 좋습니다. 그것이 그대로,이 대답은 문제가 있습니다. – chux

답변

1

문자열이 유효한 부동 소수점 값인지 테스트하려면 strtod을 사용하십시오. 정확성 확인하는 지름길이없는, 완전히 분석만큼이나 어렵다

char *p; 

errno = 0; 
double f = strtod(str,&p); 
if (errno) { 
    printf("conversion failed"); 
} 
if (strlen(str)==0) { 
    printf("empty string\n"); 
} else { 
    printf("f=%f\n", f); 
    if (*p == 0) { 
     printf("entire string valid\n"); 
    } else { 
     printf("extra characters: %s\n", p); 
    } 
} 
+2

'strtod()'는 16 진수 부동 소수점 표현뿐만 아니라 무한대와 NaN의 텍스트 표현을 받아들이고 변환하므로 입력과 반환 값을 거절해야 할 경우 더 테스트해야한다는 점에 유의해야합니다. –

+0

strtol로 처리 할 방법이 없을까요? – terribleProgrammer

+0

@terribleProgrammer Curious, 왜 strtol()을 사용하고 싶습니까? – chux

0

:이 기능은 선택적 소수점 및 선택적 지수 지정자 ("E"또는 "E")와 숫자 문자열을 구문 분석합니다. 필자는 임의의 정밀도 라이브러리를 수정하고 여전히 천박한 혼란스러운 것 중 하나는 문자열 파싱이므로, 제한된 상태 머신을 설정하고 (적절한 단축키를 사용하여) 적절하게 구현했다. 거의 500 줄의 코드. 나는 단순한 'double'을 테스트 용으로 사용했다. (사용하지 않고 에러가 너무 크다!) 몇 가지 간단한 테스트를 할 수있다.

동일한 이진 지수 및 지수 마커 p을 표준화 된 16 진수 숫자로 사용하면 8 진수도 허용한다는 점에 유의하십시오. strtod은 인정하지 않습니다.

오, 나는 꽤 버그가 있다는 것을 확신합니다.

#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 

// for pow() only 
#include <math.h> 


#ifdef DEBUG 
# define PUTS(x) puts(x) 
#else 
# define PUTS(x) 
#endif 


#define FSM_OK  1 
#define FSM_ERROR 0 

/* 
    EBNF (ISO 14977) for the real numbers this code should be able to treat correctly. 

    (* sign *) 
    sign = '+'|'-'; 

    (* numbers starting with zero are octal, hence the special treatment for zero *) 
    zero = '0'; 

    (* binary digit *) 
    bindig = '1'; 
    (* binary integer *) 
    binint = bindig , [{(zero | bindig)}]; 

    (* octal digit *); 
    octdig = bindig|'2'|'3'|'4'|'5'|'6'|'7'; 
    (* octal integer *) 
    octint = octdig , [{(zero | octdig)}]; 

    (* decimal digit *) 
    decdig = octdig|'8'|'9'; 
    (* decimal integer *) 
    decint = decdig , [{(zero | decdig)}]; 

    (* hexadecimal digit *) 
    hexdig = decdig |'A'|'B'|'C'|'D'|'E'|'F'|'a'|'b'|'c'|'e'|'f'; 
    (* hexadecimal integer *) 
    hexint = hexdig , [{(zero | hexdig)}]; 

    (* prefix for the base; inclusion of octal numbers made it interesting *) 
    prefix = '0'; 
    (* Implementing only the four main bases has been deemed sufficient *) 
    binbase = prefix , ('B'|'b'); 
    octbase = prefix , octdig; 
    hexbase = prefix , ('X'|'x'); 

    (* decimal point *) 
    decpoint = '.'; 

    (* exponents *) 
    expobin = ('P'|'p'), [sign], decint; 
    expodec = ('E'|'e'), [sign], decint; 

    (* thousands separator *) 
    (* tsep = ','|'\''|'_'; *) 

    (* "xyz", "xyz.", "xyz.zyx", ".zyx" *) 
    stubrealbin = binint | (binint, decpoint, [binint]) | (decpoint, binint); 
    stubrealoct = octint | (octint, decpoint, [octint]) | (decpoint, octint); 
    stubrealdec = decint | (decint, decpoint, [decint]) | (decpoint, decint); 
    stubrealhex = hexint | (hexint, decpoint, [hexint]) | (decpoint, hexint); 

    fullrealbin = [sign], binbase, stubrealbin, [expobin]; 
    fullrealoct = [sign], octbase, stubrealoct, [expobin]; 
    fullrealdec = [sign],   stubrealdec, [expodec]; 
    fullrealhex = [sign], hexbase, stubrealhex, [expobin]; 

    (* "InF" and "NaN" should be case insensitive in praxi *) 
    real = ([sign], "Inf") | "NaN" | fullrealbin | fullrealoct | fullrealdec | fullrealhex; 



    Input characters (grouped for clarity. Case sensitive for brevity only!). 
    The input is case insensitive, so 'e', 'E', 'b', and 'B' are only 
    distinguishable by context: once you have hexdigits 'e' and 'b' are hexdigits 
    and a following sign must trigger an error 

    '0' 
    '1'      = bin 
    '2'|'3'|'4'|'5'|'6'|'7' = oct 
    '8'|'9'     = dec 
    'A'| |'C'|'D' |'F' = hex 
    'x' 
    'b' 
    'e' 
    'p' 
    '.' 
    '+' | '-'    = sgn 

    Any other input character is not valid (state: ERROR), "Inf" and "NaN" get handled 
    elsewhere to keep things simple. 


    States 

    START 
    SIGN 
    PREFIX 
    DECPOINT 
    DECFRAC 
    BINBASE 
    OCTBASE 
    DECBASE 
    HEXBASE 
    BINFRAC 
    OCTFRAC 
    HEXFRAC 
    EXPOMARK 
    EXPOSIGN 
    EXPONENT 
    ERROR 

    Transition table 

    START '0' it is a prefix    PREFIX 
      bin it is a binary digit  DECBASE 
      oct it is an octal digit  DECBASE 
      dec it is a decimal digit  DECBASE 
      hex it is a hexadecimal digit HEXBASE 
      'x' cannot be     ERROR 
      'b' it is a hexadecimal digit HEXBASE 
      'e' it is a hexadecimal digit HEXBASE 
      'p' cannot be     ERROR 
      '.' a decimal point    DECPOINT (!) 
      sgn a sign      SIGN 

    SIGN '0' it is a prefix    PREFIX 
      bin it is a binary digit  DECBASE 
      oct it is an octal digit  DECBASE 
      dec it is a decimal digit  DECBASE 
      hex it is a hexadecimal digit HEXBASE 
      'x' cannot be     ERROR 
      'b' it is a hexadecimal digit HEXBASE 
      'e' it is a hexadecimal digit HEXBASE 
      'p' cannot be     ERROR 
      '.' a decimal point    DECPOINT (!) 
      sgn a sign      ERROR 

    PREFIX '0' zero      OCTBASE 
      bin binary digit    OCTBASE 
      oct octal digit     OCTBASE 
      dec cannot be     ERROR 
      hex cannot be     ERROR 
      'x' hexadecimal number   HEXBASE 
      'b' binary number    BINBASE 
      'e' cannot be     ERROR 
      'p' cannot be     ERROR 
      '.' decimal point    DECFRAC 
      sgn cannot be     ERROR 

    The only place, that is still lingering in limbo is the decimal point. We 
    need to fork again, but we do not know in which base the integral part (if one 
    exists at all) is, so we still take "decimal" to be the default base. 


    DECPOINT '0' binary digit    DECFRAC 
      bin binary digit    DECFRAC 
      oct octal digit    DECFRAC 
      dec decimal digit    DECFRAC 
      hex hexadecimal digit   HEXFRAC 
      'x' cannot be     ERROR 
      'b' hexadecimal digit   HEXFRAC 
      'e' hexadecimal digit   HEXFRAC 
      'p' binary exponent   EXPOMARK 
      '.' decimal point    ERROR 
      sgn cannot be     ERROR 

    A fractional part in decimal base is simple enough 

    DECFRAC '0' binary digit    DECFRAC 
      bin binary digit    DECFRAC 
      oct octal digit    DECFRAC 
      dec decimal digit    DECFRAC 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' exponent delimiter   EXPOMARK 
      'p' cannot be     ERROR 
      '.' cannot be     ERROR 
      sgn cannot be     ERROR 

    All other fractions need a base, so handle bases first 

    BINBASE '0' binary digit    BINBASE 
      bin binary digit    BINBASE 
      oct cannot be     ERROR 
      dec cannot be     ERROR 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' exponent delimiter   EXPOMARK 
      '.' decimal point    BINFRAC 
      sgn cannot be     ERROR 

    OCTBASE '0' binary digit    OCTBASE 
      bin binary digit    OCTBASE 
      oct octal digit    OCTBASE 
      dec cannot be     ERROR 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' exponent delimiter   EXPOMARK 
      '.' decimal point    OCTFRAC 
      sgn cannot be     ERROR 

    HEXBASE '0' binary digit    HEXBASE 
      bin binary digit    HEXBASE 
      oct octal digit    HEXBASE 
      dec decimal digit    HEXBASE 
      hex hexadecimal digit   HEXBASE 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' exponent delimiter   EXPOMARK 
      '.' decimal point    HEXFRAC 
      sgn cannot be     ERROR 

    It is easy now to fill the gaps. 

    BINFRAC '0' binary digit    BINFRAC 
      bin binary digit    BINFRAC 
      oct cannot be     ERROR 
      dec cannot be     ERROR 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' exponent delimiter   EXPOMARK 
      '.' cannot be     ERROR 
      sgn cannot be     ERROR 

    OCTFRAC '0' binary digit    OCTFRAC 
      bin binary digit    OCTFRAC 
      oct octal digit    OCTFRAC 
      dec cannot be     ERROR 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' exponent delimiter   EXPOMARK 
      '.' cannot be     ERROR 
      sgn cannot be     ERROR 

    HEXFRAC '0' binary digit    HEXFRAC 
      bin binary digit    HEXFRAC 
      oct octal digit    HEXFRAC 
      dec decimal digit    HEXFRAC 
      hex hexadecimal digit   HEXFRAC 
      'x' cannot be     ERROR 
      'b' hexadecimal digit   HEXFRAC 
      'e' hexadecimal digit   HEXFRAC 
      'p' exponent delimiter   EXPOMARK 
      '.' decimal point    ERROR 
      sgn cannot be     ERROR 

    The exponent is always encoded in decimal base (IEEE 754 (ISO/IEC 60559) sec. 5.12.3 for 
    the hexadecimal example) 

    EXPOMARK '0' binary digit    EXPONENT 
      bin binary digit    EXPONENT 
      oct octal digit    EXPONENT 
      dec decimal digit    EXPONENT 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' cannot be     ERROR 
      '.' cannot be     ERROR 
      sgn sign      EXPOSIGN 

    EXPOSIGN '0' binary digit    EXPONENT 
      bin binary digit    EXPONENT 
      oct octal digit    EXPONENT 
      dec decimal digit    EXPONENT 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' cannot be     ERROR 
      '.' cannot be     ERROR 
      sgn sign      ERROR 

    EXPONENT '0' binary digit    EXPONENT 
      bin binary digit    EXPONENT 
      oct octal digit    EXPONENT 
      dec decimal digit    EXPONENT 
      hex cannot be     ERROR 
      'x' cannot be     ERROR 
      'b' cannot be     ERROR 
      'e' cannot be     ERROR 
      'p' cannot be     ERROR 
      '.' cannot be     ERROR 
      sgn sign      ERROR 

    ERROR nothing follows an error, only more ERROR 

    Nothing marking an end-state, it is just the end of the input buffer 


ZERO  '0' 
BINDIG '1' 
OCTDIG '2'|'3'|'4'|'5'|'6'|'7' 
DECDIG '8'|'9' 
HEXDIG 'A'| |'C'|'D' |'F' 
PREHEX 'x' 
PREBIN 'b' 
EXPDEC 'e' 
EXPBIN 'p' 
DECPNT '.' 
SGNCHR  '+' | '-' 

      ZERO BINDIG OCTDIG DECDIG HEXDIG PREHEX PREBIN EXPDEC EXPBIN DECPNT SGNCHR 
START  PREFIX DECBASE DECBASE DECBASE HEXBASE ERROR HEXBASE HEXBASE ERROR DECPOINT SIGN 
SIGN  PREFIX DECBASE DECBASE DECBASE HEXBASE ERROR HEXBASE HEXBASE ERROR DECPOINT ERROR 
PREFIX OCTBASE OCTBASE OCTBASE ERROR ERROR HEXBASE BINBASE ERROR ERROR DECFRAC ERROR 
DECPOINT DECFRAC DECFRAC DECFRAC DECFRAC HEXFRAC ERROR HEXFRAC HEXFRAC EXPOMARK ERROR ERROR 
DECFRAC DECFRAC DECFRAC DECFRAC DECFRAC ERROR ERROR ERROR EXPOMARK ERROR ERROR ERROR 
BINBASE BINBASE BINBASE ERROR ERROR ERROR ERROR ERROR ERROR EXPOMARK BINFRAC ERROR 
OCTBASE OCTBASE OCTBASE OCTBASE ERROR ERROR ERROR ERROR ERROR EXPOMARK OCTFRAC ERROR 
DECBASE DECBASE DECBASE DECBASE ERROR ERROR ERROR ERROR EXPOMARK ERROR DECFRAC ERROR 
HEXBASE HEXBASE HEXBASE HEXBASE HEXBASE HEXBASE ERROR ERROR ERROR EXPOMARK HEXFRAC ERROR 
BINFRAC BINFRAC BINFRAC ERROR ERROR ERROR ERROR ERROR ERROR EXPOMARK ERROR ERROR 
OCTFRAC OCTFRAC OCTFRAC OCTFRAC ERROR ERROR ERROR ERROR ERROR EXPOMARK ERROR ERROR 
HEXFRAC HEXFRAC HEXFRAC HEXFRAC HEXFRAC HEXFRAC ERROR HEXFRAC HEXFRAC EXPOMARK ERROR ERROR 
EXPOMARK EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR EXPOSIGN 
EXPOSIGN EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR ERROR 
EXPONENT EXPON'T EXPON'T EXPON'T EXPON'T ERROR ERROR ERROR ERROR ERROR ERROR ERROR 
ERROR  ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR ERROR 
*/ 


#if !(defined _BSD_SOURCE || defined _DEFAULT_SOURCE || _POSIX_C_SOURCE >= 200112L) 
# include <ctype.h> 
static int strncasecmp(const char *s1, const char *s2, size_t n) 
{ 
    char c1 = 0; 
    char c2 = 0; 

    while (n--) { 
    c1 = tolower(*s1); 
    c2 = tolower(*s2); 

    if (c1 != c2) { 
     break; 
    } 
    if (c1 == '\0') { 
     break; 
    } 
    s1++; 
    s2++; 
    } 
    return (int) (c1 - c2); 
} 
#endif 

#ifdef _MSC_VER 
#define strncasecmp(x,y,z) _strnicmp(x,y,z) 
#endif 


enum fsm_input { 
    ZERO,       // '0' 
    BINDIG,      // '1' 
    OCTDIG,      // '2'|'3'|'4'|'5'|'6'|'7' 
    DECDIG,      // '8'|'9' 
    HEXDIG,      // 'A' |'C'|'D' |'F' 
    PREHEX,      // 'x' 
    PREBIN,      // 'b' 
    EXPDEC,      // 'e' 
    EXPBIN,      // 'p' 
    DECPNT,      // '.' 
    SGNCHR,      // '+' | '-' 
    OTHER 
}; 

enum fsm_states { 
    START, 
    SIGN, 
    PREFIX, 
    DECPOINT, 
    DECFRAC, 
    BINBASE, 
    OCTBASE, 
    DECBASE, 
    HEXBASE, 
    BINFRAC, 
    OCTFRAC, 
    HEXFRAC, 
    EXPOMARK, 
    EXPOSIGN, 
    EXPONENT, 
    ERROR 
}; 

#ifdef DEBUG 
static const char *st2str[16] = { 
    "START", 
    "SIGN", 
    "PREFIX", 
    "DECPOINT", 
    "DECFRAC", 
    "BINBASE", 
    "OCTBASE", 
    "DECBASE", 
    "HEXBASE", 
    "BINFRAC", 
    "OCTFRAC", 
    "HEXFRAC", 
    "EXPOMARK", 
    "EXPOSIGN", 
    "EXPONENT", 
    "ERROR" 
}; 
#endif 
// transition-table 
static int fsm_table[16][11] = { 
    {PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE, HEXBASE, ERROR, 
    DECPOINT, SIGN}, 
    {PREFIX, DECBASE, DECBASE, DECBASE, HEXBASE, ERROR, HEXBASE, 
    HEXBASE, ERROR, DECPOINT, ERROR}, 
    {OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, HEXBASE, BINBASE, ERROR, ERROR, 
    DECFRAC, 
    ERROR}, 
    {DECFRAC, DECFRAC, DECFRAC, DECFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC, 
    EXPOMARK, ERROR, ERROR}, 
    {DECFRAC, DECFRAC, DECFRAC, DECFRAC, ERROR, ERROR, ERROR, EXPOMARK, ERROR, 
    ERROR, ERROR}, 
    {BINBASE, BINBASE, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, 
    BINFRAC, ERROR}, 
    {OCTBASE, OCTBASE, OCTBASE, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, 
    OCTFRAC, ERROR}, 
    {DECBASE, DECBASE, DECBASE, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR, 
    DECFRAC, ERROR}, 
    {HEXBASE, HEXBASE, HEXBASE, HEXBASE, HEXBASE, ERROR, ERROR, ERROR, EXPOMARK, 
    HEXFRAC, ERROR}, 
    {BINFRAC, BINFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, ERROR, 
    ERROR}, 
    {OCTFRAC, OCTFRAC, OCTFRAC, ERROR, ERROR, ERROR, ERROR, ERROR, EXPOMARK, 
    ERROR, ERROR}, 
    {HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, HEXFRAC, ERROR, HEXFRAC, HEXFRAC, 
    EXPOMARK, ERROR, ERROR}, 
    {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR, 
    ERROR, EXPOSIGN}, 
    {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR, 
    ERROR, ERROR}, 
    {EXPONENT, EXPONENT, EXPONENT, EXPONENT, ERROR, ERROR, ERROR, ERROR, ERROR, 
    ERROR, ERROR}, 
    {ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR, ERROR} 
}; 


#include <ctype.h> 
static int check_type(char c) 
{ 
    int type; 
    switch (tolower(c)) { 
    case '0': 
     type = ZERO; 
     break; 
    case '1': 
     type = BINDIG; 
     break; 
    case '2': 
    case '3': 
    case '4': 
    case '5': 
    case '6': 
    case '7': 
     type = OCTDIG; 
     break; 
    case '8': 
    case '9': 
     type = DECDIG; 
     break; 
    case 'a': 
    case 'c': 
    case 'd': 
    case 'f': 
     type = HEXDIG; 
     break; 
    case 'x': 
     type = PREHEX; 
     break; 
    case 'b': 
     type = PREBIN; 
     break; 
    case 'e': 
     type = EXPDEC; 
     break; 
    case 'p': 
     type = EXPBIN; 
     break; 
    case '.': 
     type = DECPNT; 
     break; 
    case '+': 
    case '-': 
     type = SGNCHR; 
     break; 
    default: 
     type = OTHER; 
     break; 
    }; 
    return type; 
} 

// some variables to hold the relevant parts of a real number 
static int main_sign = 1; 
static int expo_sign = 1; 

static double integral_part = 0.0; 
static double fractional_part = 0.0; 
static int hex_frac = 0; 
static int dec_frac = 0; 
static int oct_frac = 0; 
static int bin_frac = 0; 

static int exponent_part = 0; 
// flags with both a boolean and a numerical value 
// prob. not the best idea but simple 
#define DECIMAL_EXP 10 
#define BINARY_EXP 2 
static int exponent_binordec = 0; 

// assuming ASCII. Full map for more bases in the future. 
// Far future. 
static const char digit_map[] = { 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x00-0x07 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x08-0x0f 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x10-0x17 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x18-0x1f 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x20-0x27 
    -1, -1, 1, -1, -1, -1, -1, -1,  // 0x28-0x2f '+' = 0x2b, '-' = 0x2d 
    0, 1, 2, 3, 4, 5, 6, 7,  // 0x30-0x37 
    8, 9, -1, -1, -1, -1, -1, -1,  // 0x38-0x3F 
    -1, 10, 11, 12, 13, 14, 15, -1,  // 0x40-0x47 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x48-0x4f 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x50-0x57 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x58-0x5f 
    -1, 10, 11, 12, 13, 14, 15, -1,  // 0x60-0x67 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x68-0x6f 
    -1, -1, -1, -1, -1, -1, -1, -1,  // 0x70-0x77 
    -1, -1, -1, -1, -1, -1, -1, -1  // 0x78-0x7f 
}; 


static int fsm(char input, int *state) 
{ 
    int res = FSM_OK; 

    input = tolower(input); 
#ifdef DEBUG 
    printf("INPUT: %c [0x%2x] (%d) STATE: %-10s\n", input, input,digit_map[+input],st2str[*state]); 
#endif 
    switch (*state) { 
    case START: 
     fprintf(stderr, 
       "Something is messed up in quite some hefty way and form!\n"); 
     exit(EXIT_FAILURE); 
    case SIGN: 
     main_sign = digit_map[+input]; 
     break; 
    case PREFIX: 
     // not used 
     break; 
    case DECPOINT: 
     // not used 
     break; 
    case DECBASE: 
     integral_part *= 10.0; 
     integral_part += digit_map[+input]; 
     break; 
    case BINBASE: 
     integral_part *= 2.0; 
     integral_part += digit_map[+input]; 
     break; 
    case OCTBASE: 
     integral_part *= 8.0; 
     integral_part += digit_map[+input]; 
     break; 
    case HEXBASE: 
     if (input == 'x') { 
     break; 
     } 
     integral_part *= 16.0; 
     integral_part += digit_map[+input]; 
     break; 
    case BINFRAC: 
     if (input == '.') { 
     break; 
     } 
     fractional_part *= 2.0; 
     fractional_part += digit_map[+input]; 
     bin_frac++; 
     break; 
    case OCTFRAC: 
     if (input == '.') { 
     break; 
     } 
     fractional_part *= 8.0; 
     fractional_part += digit_map[+input]; 
     oct_frac++; 
     break; 
    case DECFRAC: 
     if (input == '.') { 
     break; 
     } 
     fractional_part *= 10.0; 
     fractional_part += digit_map[+input]; 
     dec_frac++; 
     break; 
    case HEXFRAC: 
     if (input == '.') { 
     break; 
     } 
     fractional_part *= 16.0; 
     fractional_part += digit_map[+input]; 
     hex_frac++; 
     break; 
    case EXPOMARK: 
     exponent_binordec = (input == 'e') ? DECIMAL_EXP : BINARY_EXP; 
     break; 
    case EXPOSIGN: 
     expo_sign = digit_map[+input]; 
     break; 
    case EXPONENT: 
     exponent_part *= 10; 
     exponent_part += digit_map[+input]; 
     break; 
    case ERROR: 
     fprintf(stderr, "ERROR state reached\n"); 
     exit(EXIT_FAILURE); 
     // "Run in circles, scream and shout!" 
     // Infantry Journal, Vol. 35, p. 396, United States Infantry Association, 1929 
     // Or was it Herman Wouk? The Caine Mutiny? No, that would be 1951 and too late. 
     break; 
    default: 
     fprintf(stderr, "Unexpected state with input %c\n", input); 
     *state = ERROR; 
     res = FSM_ERROR; 
     break; 
    } 
    return res; 
} 

static char *trim_both(char *s) 
{ 
    char *end,*p; 
    p = s; 
    while (isspace(*p)) { 
    p++; 
    } 
    if (*p == '\0') { 
    return p; 
    } 
    end = p + strlen(p) - 1; 
    while (end > p && isspace(*end)) { 
    end--; 
    } 
    *(end + 1) = '\0'; 
    return p; 
} 

static int str2dbl(char *s, double *d) 
{ 
    int cur_state = START; 
    int type; 
    int res; 

    s = trim_both(s); 

    if(*s == '\0'){ 
    // empty input, would an error be better? 
    *d = 0.0; 
    return FSM_OK; 
    } 

    if(*s == '0' && *(s+1) == '\0'){ 
    *d = 0.0; 
    return FSM_OK; 
    } 

    if (!strncasecmp(s, "-inf", 4)) { 
    *d = -INFINITY; 
    return FSM_OK; 
    } 
    if (!strncasecmp(s, "+inf", 4) || !strncasecmp(s, "inf", 3)) { 
    *d = INFINITY; 
    return FSM_OK; 
    } 
    if (!strncasecmp(s, "-nan", 4) || !strncasecmp(s, "+nan", 4) || !strncasecmp(s, "nan", 3)) { 
    *d = NAN; 
    return FSM_OK; 
    } 

    while (*s != '\0') { 
    type = check_type(*s); 
    if (type == OTHER) { 
     fprintf(stderr, "OTHER: %c", *s); 
     return FSM_ERROR; 
    } 

    cur_state = fsm_table[cur_state][type]; 
    res = fsm(*s, &cur_state); 
    if (res != FSM_OK) { 
     break; 
    } 
    s++; 
    } 

    printf("exp; %d, intp: %.20g, fracp: %.20g\n", exponent_part, integral_part, 
     fractional_part); 

    // The following will work with arbitray precision in production, use of 
    // a "double" is just for testing and not for real use. The error is 
    // larger than one ulp in way too many times 

    // the integral part needs no treatment, yet. 
    *d += integral_part; 

    // the fractional part needs to be shifted by the base to the right 
    if (hex_frac > 0) { 
    fractional_part /= pow(16, hex_frac); 
    } else if (dec_frac > 0) { 
    fractional_part /= pow(10, dec_frac); 
    } else if (oct_frac > 0) { 
    fractional_part /= pow(8, oct_frac); 
    } else if (bin_frac > 0) { 
    fractional_part /= pow(2, bin_frac); 
    } 
    printf("fracp: %.20g\n", fractional_part); 
    *d += fractional_part; 

    // (exponent_binordec != 0) also means that there is an exponent in the first place 
    if (exponent_binordec) { 
    if (expo_sign >= 0) { 
     *d *= pow(exponent_binordec, exponent_part); 
    } else { 
     *d /= pow(exponent_binordec, exponent_part); 
    } 
    } 
    *d *= main_sign; 
    return FSM_OK; 
} 

int main(int argc, char **argv) 
{ 
    int res; 
    char *input, *endptr; 
    double out, libc; 

    if (argc != 2) { 
    fprintf(stderr, "Usage: %s float\n", argv[0]); 
    exit(EXIT_FAILURE); 
    } 

    input = malloc(strlen(argv[1]) + 1); 
    if (input == NULL) { 
    fprintf(stderr, "Malloc failed to allocate a measly %zu bytes\n", 
      strlen(argv[1]) + 1); 
    exit(EXIT_FAILURE); 
    } 
    strcpy(input, argv[1]); 

    // all checks ommited! 
    libc = strtod(input, &endptr); 
    printf("\nINPUT: %s\t%g\t%s\n\n", input, libc, endptr); 
    out = 0.0; 

    res = str2dbl(input, &out); 

    printf 
     ("fsm returned %d and the result (if any) is: \n\tinp: %s\n\town: %.20g\n\tlibc: %.20g\n", 
     res, trim_both(input) ,out, libc); 
    free(input); 
    exit(EXIT_SUCCESS); 
} 
관련 문제