0

i wrote a atof function which named atof_beta.i run it, but the result was not the same as atof's result.

for example: input:1111111111111111111111111111111111111111111111111111111111111111111111111111111111

output:(fabs(val-atof(s)) <= EPSILON) equal zero.

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <limits.h>
#include <float.h>
#include <math.h>

double check_overflow(double val)
{
    if (val > DBL_MAX){
        return DBL_MAX;
    }else if (val <  DBL_MIN){
        return DBL_MIN;
    }
    return val;
}


double get_exp(char *s)
{
    double exp = 10;
    int num = 0x00;
    char c = *s;

    if (c == '-'){
        exp = 0.1;
        s++;
    }else if (c == '+'){
        s++;
    }

    while ((c = *s++) != '\0'){
        if ((c >= '0') && (c <= '9')){
            num = num*10 + c - '0';
        }
        else{
            return 0x01;
        }
    }

    double tmp = 0x01;
    while (num--){
        tmp *= exp;
    }

    return tmp;
}

double atof_beta(char *s)
{
    double integer = 0x00;
    double fraction = 0x00;
    int sign = 0x01;
    int fraction_flag = 0x00;
    double divisor = 0x01;
    double exp = 0x01;

    char c = *s;

    if (c == '-'){
        sign = -1;
        s++;
    }else if (c == '+'){
        sign = 1;
        s++;
    }

    while ((c = (*s++)) != '\0'){
        if ((c >= '0') && (c <= '9')){
            if (!fraction_flag){
                integer = integer*10 + (c -'0');
            }else{
                fraction = fraction*10 + c -'0';
                divisor *= 10;
            }
        }else if (c == '.'){
            fraction_flag = 0x01;
        }else if ((c == 'e') || (c == 'E')){
            exp = get_exp(s);
            break;
        }else{
            break;
        }
    }

    integer = check_overflow(integer);
    fraction = check_overflow(fraction);
    exp = check_overflow(exp);
    double val = sign*((integer + (fraction/divisor))*exp);
    return check_overflow(val);
}

#define EPSILON 1e-6
void main()
{
    char s[1024], *p;
    double val;

    while(1)
    {
        printf("enter string : ");
        fgets(s, sizeof(s), stdin);
        if ((p = strchr(s, '\n')) != NULL) { 
            *p = '\0'; /* Remove newline */
        }
        puts(s); /* No need to cast */
        val = atof_beta(s);
        printf("\nfinal value : %lf, %lf, %d\n", val, atof(s), (fabs(val-atof(s)) <= EPSILON));
    }

    return;
}
David Ranieri
  • 39,972
  • 7
  • 52
  • 94
Don7 Hao
  • 11
  • 3
  • 1
    See [Why is the `gets()` function dangerous?](http://stackoverflow.com/questions/1694036/why-is-the-gets-function-dangerous-why-should-it-not-be-used) and [What should `main()` return in C and C++](http://stackoverflow.com/questions/204476/what-should-main-return-in-c-and-c/18721336#18721336) – Jonathan Leffler Feb 03 '15 at 07:22
  • 1
    Note that if the input value is small enough, the test `(fabs(val-atof(s)) <= EPSILON)` is meaningless. For example, 0.000000009 as input will be printed as zero (because `%f` prints to 6 decimal places), and it wouldn't matter if your code converted the 9 into a 4 — the absolute difference would still be less than your EPSILON. You need to use a relative difference, such as `(fabs(val-atof(s)) / max(fabs(val), fabs(atof(s))) <= EPSILON)`. – Jonathan Leffler Feb 03 '15 at 07:31
  • Pedantic note: `while ((c = *s++) != '\0'){` has not protection from overflow. – chux - Reinstate Monica Feb 03 '15 at 13:57

1 Answers1

1

This is wrong:

char *s;
... 
printf("enter string : ");
s = (char *)malloc(sizeof(char));
gets((char *)s);
puts((const char *)s);

You reserve space for a single char but you want a string, also note that gets was deprecated in C99 and C11 removed it, I suggest fgets:

char s[32], *p;
...
printf("enter string : ");
/* No need to malloc */
fgets(s, sizeof s, stdin);
if ((p = strchr(s, '\n')) != NULL) { 
    *p = '\0'; /* Remove newline */
}
puts(s); /* No need to cast */
David Ranieri
  • 39,972
  • 7
  • 52
  • 94