mirror of https://github.com/flysand7/ciabatta.git
				
				
				
			strtod, strtof, strtold
This commit is contained in:
		
							parent
							
								
									e18e9a988e
								
							
						
					
					
						commit
						7b6bea0ff1
					
				| 
						 | 
				
			
			@ -4,10 +4,10 @@
 | 
			
		|||
#include <stdbool.h>
 | 
			
		||||
#include <limits.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <math.h>
 | 
			
		||||
 | 
			
		||||
// TODO: strto*: locale-based parsing for integers
 | 
			
		||||
// TODO: i made a function that parses longs and i'm fucken
 | 
			
		||||
// tired. someone make float parsing :kekw:
 | 
			
		||||
// TODO: strto*: locale-based parsing
 | 
			
		||||
// TODO: correctly rounded base 16 floats parsing
 | 
			
		||||
 | 
			
		||||
// Call me weak if you want but I'm actually too lazy to type
 | 
			
		||||
// them out every time, also they take up a lot of horiz space.
 | 
			
		||||
| 
						 | 
				
			
			@ -36,8 +36,20 @@ static bool isbase(int c, int base) {
 | 
			
		|||
    return val < base;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static bool
 | 
			
		||||
strprefix_i(char const *restrict str, char const *restrict prefix)
 | 
			
		||||
{
 | 
			
		||||
    while(*prefix != 0) {
 | 
			
		||||
        if(*str == 0) break;
 | 
			
		||||
        if(toupper(*str) != toupper(*prefix)) return false;
 | 
			
		||||
        ++prefix;
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    return true;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Called only when isbase(c, base) for some base in range
 | 
			
		||||
static long todigitl(int c) {
 | 
			
		||||
static long todigit(int c) {
 | 
			
		||||
    int val;
 | 
			
		||||
    if(isdigit(c)) {
 | 
			
		||||
        val = c-'0';
 | 
			
		||||
| 
						 | 
				
			
			@ -51,7 +63,7 @@ static long todigitl(int c) {
 | 
			
		|||
    return val;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static intull strto_generic(
 | 
			
		||||
static intull strtoi_generic(
 | 
			
		||||
    const char *restrict nptr,
 | 
			
		||||
    char **restrict endptr,
 | 
			
		||||
    int inbase,
 | 
			
		||||
| 
						 | 
				
			
			@ -89,7 +101,7 @@ static intull strto_generic(
 | 
			
		|||
    }
 | 
			
		||||
    // See if we need to parse base in C-like format
 | 
			
		||||
    // then set the base accordingly
 | 
			
		||||
    if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) {
 | 
			
		||||
    if(strprefix_i(str, "0X")) {
 | 
			
		||||
        ++str;
 | 
			
		||||
        if(base == 16 || base == 0) {
 | 
			
		||||
            ++str;
 | 
			
		||||
| 
						 | 
				
			
			@ -109,7 +121,7 @@ static intull strto_generic(
 | 
			
		|||
    // Parse the string of digits in the given base. If the value
 | 
			
		||||
    // exceeds abs(int_min) we exit with range error.
 | 
			
		||||
    while(isbase(*str, (int)base)) {
 | 
			
		||||
        intull digit = (intull)todigitl(*str);
 | 
			
		||||
        intull digit = (intull)todigit(*str);
 | 
			
		||||
        if(value > (int_abs_max - digit)/base) {
 | 
			
		||||
            goto error_out_of_range;
 | 
			
		||||
        }
 | 
			
		||||
| 
						 | 
				
			
			@ -152,10 +164,126 @@ finish:
 | 
			
		|||
    return value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static double strtod_generic(
 | 
			
		||||
    const char *restrict nptr,
 | 
			
		||||
    char **restrict endptr
 | 
			
		||||
) {
 | 
			
		||||
    const char *restrict str = nptr;
 | 
			
		||||
    bool conv_performed = false;
 | 
			
		||||
    double value = 0.0;
 | 
			
		||||
    double coef = 1.0;
 | 
			
		||||
    // Skip space on the beginning
 | 
			
		||||
    while(isspace(*str)) {
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    // Check for inf and nan
 | 
			
		||||
    if(strprefix_i(str, "INF")) {
 | 
			
		||||
        str += sizeof "INF"-1;
 | 
			
		||||
        value = HUGE_VAL;
 | 
			
		||||
        conv_performed = true;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if(strprefix_i(str, "INFINITY")) {
 | 
			
		||||
        str += sizeof "INFINITY"-1;
 | 
			
		||||
        value = HUGE_VAL;
 | 
			
		||||
        conv_performed = true;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    if(strprefix_i(str, "NAN")) {
 | 
			
		||||
        str += sizeof "NAN"-1;
 | 
			
		||||
        value = NAN;
 | 
			
		||||
        conv_performed = true;
 | 
			
		||||
        if(*str == '(') {
 | 
			
		||||
            while(*str != ')') {
 | 
			
		||||
                ++str;
 | 
			
		||||
            }
 | 
			
		||||
            ++str;
 | 
			
		||||
        }
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    // Parse C float
 | 
			
		||||
    if(*str == '+') {
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    else if(*str == '-') {
 | 
			
		||||
        coef = -1.;
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    int base = 10;
 | 
			
		||||
    if(strprefix_i(str, "0X")) {
 | 
			
		||||
        str += sizeof "0X"-1;
 | 
			
		||||
        base = 16;
 | 
			
		||||
    }
 | 
			
		||||
    // Parse the whole part
 | 
			
		||||
    while(isbase(*str, base)) {
 | 
			
		||||
        long digit = todigit(*str);
 | 
			
		||||
        value = 10.0*value + (double)digit;
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    if(*str != '.') {
 | 
			
		||||
        value = 0.0;
 | 
			
		||||
        goto finish;
 | 
			
		||||
    }
 | 
			
		||||
    ++str;
 | 
			
		||||
    // Parse the fractional part
 | 
			
		||||
    long exp = 1;
 | 
			
		||||
    while(isbase(*str, base)) {
 | 
			
		||||
        long digit = todigit(*str);
 | 
			
		||||
        double fract = (double)digit;
 | 
			
		||||
        long cexp = exp;
 | 
			
		||||
        while(cexp-- != 0) {
 | 
			
		||||
            fract /= (double)base;
 | 
			
		||||
        }
 | 
			
		||||
        value += fract;
 | 
			
		||||
        ++exp;
 | 
			
		||||
        ++str;
 | 
			
		||||
    }
 | 
			
		||||
    // Parse the exponent
 | 
			
		||||
    if((base == 10 && strprefix_i(str, "E"))
 | 
			
		||||
    || (base == 16 && strprefix_i(str, "P")))
 | 
			
		||||
    {
 | 
			
		||||
        ++str;
 | 
			
		||||
        long exp = 0;
 | 
			
		||||
        long exp_coef = 1;
 | 
			
		||||
        if(*str == '+') {
 | 
			
		||||
            ++str;
 | 
			
		||||
        }
 | 
			
		||||
        else if(*str == '-') {
 | 
			
		||||
            exp_coef = -1;
 | 
			
		||||
            ++str;
 | 
			
		||||
        }
 | 
			
		||||
        while(isdigit(*str)) {
 | 
			
		||||
            exp = 10*exp + (long)(*str-'0');
 | 
			
		||||
            ++str;
 | 
			
		||||
        }
 | 
			
		||||
        if(exp_coef == 1) {
 | 
			
		||||
            while(exp--!=0) value = value * base;
 | 
			
		||||
        }
 | 
			
		||||
        else if(exp_coef == -1) {
 | 
			
		||||
            while(exp--!=0) value = value / base;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    if(!isfinite(value)) {
 | 
			
		||||
        errno = ERANGE;
 | 
			
		||||
        value = coef*HUGE_VAL;
 | 
			
		||||
    }
 | 
			
		||||
    conv_performed = true;
 | 
			
		||||
finish:
 | 
			
		||||
    if(endptr != NULL) {
 | 
			
		||||
        if(conv_performed) {
 | 
			
		||||
            *endptr = (char *)str;
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            *endptr = (char *)nptr;
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    return coef*value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		||||
    intull int_max = (intull)LONG_MAX;
 | 
			
		||||
    intl coef;
 | 
			
		||||
    intull modulo = strto_generic(nptr, endptr, base, &coef, int_max);
 | 
			
		||||
    intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
 | 
			
		||||
    intl value;
 | 
			
		||||
    if(modulo == int_max) {
 | 
			
		||||
        value = LONG_MIN;
 | 
			
		||||
| 
						 | 
				
			
			@ -169,7 +297,7 @@ intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		|||
intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		||||
    intull int_max = (intull)LLONG_MAX;
 | 
			
		||||
    intl coef;
 | 
			
		||||
    intull modulo = strto_generic(nptr, endptr, base, &coef, int_max);
 | 
			
		||||
    intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
 | 
			
		||||
    intll value;
 | 
			
		||||
    if(modulo == int_max) {
 | 
			
		||||
        value = LLONG_MIN;
 | 
			
		||||
| 
						 | 
				
			
			@ -182,13 +310,13 @@ intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		|||
 | 
			
		||||
intul strtoul(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		||||
    intull int_max = (intull)ULONG_MAX;
 | 
			
		||||
    intull value = strto_generic(nptr, endptr, base, NULL, int_max);
 | 
			
		||||
    intull value = strtoi_generic(nptr, endptr, base, NULL, int_max);
 | 
			
		||||
    return (intul)value;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
 | 
			
		||||
    intull int_max = (intull)ULLONG_MAX;
 | 
			
		||||
    return strto_generic(nptr, endptr, base, NULL, int_max);
 | 
			
		||||
    return strtoi_generic(nptr, endptr, base, NULL, int_max);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
double atof(const char *nptr) {
 | 
			
		||||
| 
						 | 
				
			
			@ -208,13 +336,13 @@ long long int atoll(const char *nptr) {
 | 
			
		|||
}
 | 
			
		||||
 | 
			
		||||
double strtod(const char *restrict nptr, char **restrict endptr) {
 | 
			
		||||
    return 0;
 | 
			
		||||
    return strtod_generic(nptr, endptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
float strtof(const char *restrict nptr, char **restrict endptr) {
 | 
			
		||||
    return 0;
 | 
			
		||||
    return (float)strtod_generic(nptr, endptr);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
long double strtold(const char *restrict nptr, char **restrict endptr) {
 | 
			
		||||
    return 0;
 | 
			
		||||
    return (long double)strtod_generic(nptr, endptr);
 | 
			
		||||
}
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										17
									
								
								inc/math.h
								
								
								
								
							
							
						
						
									
										17
									
								
								inc/math.h
								
								
								
								
							| 
						 | 
				
			
			@ -21,11 +21,11 @@ typedef double double_t;
 | 
			
		|||
#define FP_INFINITE  1
 | 
			
		||||
#define FP_NAN       2
 | 
			
		||||
 | 
			
		||||
FP_INFINITE
 | 
			
		||||
FP_NAN
 | 
			
		||||
FP_NORMAL
 | 
			
		||||
FP_SUBNORMAL
 | 
			
		||||
FP_ZERO
 | 
			
		||||
//FP_INFINITE
 | 
			
		||||
//FP_NAN
 | 
			
		||||
//FP_NORMAL
 | 
			
		||||
//FP_SUBNORMAL
 | 
			
		||||
//FP_ZERO
 | 
			
		||||
#define FP_FAST_FMA  1
 | 
			
		||||
#define FP_FAST_FMAF 1
 | 
			
		||||
#define FP_FAST_FMAL 1
 | 
			
		||||
| 
						 | 
				
			
			@ -39,8 +39,11 @@ FP_ZERO
 | 
			
		|||
 | 
			
		||||
// TODO: implement this
 | 
			
		||||
#define fpclassify(x) 0
 | 
			
		||||
#define isfinite(x)   0
 | 
			
		||||
#define isinf(x)      0
 | 
			
		||||
 | 
			
		||||
// HACK: If its fine just remove the comment
 | 
			
		||||
#define isfinite(x)   ((double)(x) != HUGE_VAL && (double)(x) != -HUGE_VAL)
 | 
			
		||||
#define isinf(x)      (!(isinf(x)))
 | 
			
		||||
 | 
			
		||||
#define isnan(x)      0
 | 
			
		||||
#define isnormal(x)   0
 | 
			
		||||
#define signbit(x)    0
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
							
								
								
									
										57
									
								
								test/test.c
								
								
								
								
							
							
						
						
									
										57
									
								
								test/test.c
								
								
								
								
							| 
						 | 
				
			
			@ -1,44 +1,27 @@
 | 
			
		|||
#include <assert.h>
 | 
			
		||||
#include <ctype.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
#include <stddef.h>
 | 
			
		||||
#include <stdbool.h>
 | 
			
		||||
#include <stdio.h>
 | 
			
		||||
#include <errno.h>
 | 
			
		||||
#include <stdlib.h>
 | 
			
		||||
 
 | 
			
		||||
int main(void)
 | 
			
		||||
{
 | 
			
		||||
    double v0 = strtod("0X1.BC70A3D70A3D7P+6", NULL);
 | 
			
		||||
 | 
			
		||||
int main(int argc, char** argv) {
 | 
			
		||||
    const char *p = "10 200000000000000000000000000000 30 -40 junk";
 | 
			
		||||
    // printf("Parsing '%s':\n", p);
 | 
			
		||||
 
 | 
			
		||||
    for (;;)
 | 
			
		||||
    // parsing with error handling
 | 
			
		||||
    const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6  1.18973e+4932zzz";
 | 
			
		||||
    
 | 
			
		||||
    char *end;
 | 
			
		||||
    for (double f = strtod(p, &end); p != end; f = strtod(p, &end))
 | 
			
		||||
    {
 | 
			
		||||
        // errno can be set to any non-zero value by a library function call
 | 
			
		||||
        // regardless of whether there was an error, so it needs to be cleared
 | 
			
		||||
        // in order to check the error set by strtol
 | 
			
		||||
        errno = 0;
 | 
			
		||||
        char *end;
 | 
			
		||||
        const long i = strtol(p, &end, 10);
 | 
			
		||||
        if (p == end)
 | 
			
		||||
            break;
 | 
			
		||||
 
 | 
			
		||||
        const bool range_error = errno == ERANGE;
 | 
			
		||||
        // printf("Extracted '%.*s', strtol returned %ld.", (int)(end-p), p, i);
 | 
			
		||||
        // printf("'%.*s' -> ", (int)(end-p), p);
 | 
			
		||||
        p = end;
 | 
			
		||||
 
 | 
			
		||||
        // if (range_error)
 | 
			
		||||
        //     printf(" Range error occurred.");
 | 
			
		||||
 
 | 
			
		||||
        // putchar('\n');
 | 
			
		||||
        if (errno == ERANGE){
 | 
			
		||||
            // printf("range error, got ");
 | 
			
		||||
            errno = 0;
 | 
			
		||||
        }
 | 
			
		||||
        // printf("%f\n", f);
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
    // printf("Unextracted leftover: '%s'\n\n", p);
 | 
			
		||||
 
 | 
			
		||||
    // parsing without error handling
 | 
			
		||||
    long v1 = strtol("1010", NULL, 2);
 | 
			
		||||
    long v2 = strtol("12",   NULL, 8);
 | 
			
		||||
    long v3 = strtol("A",    NULL, 16);
 | 
			
		||||
    long v4 = strtol("junk", NULL, 36);
 | 
			
		||||
    long v5 = strtol("012",  NULL, 0);
 | 
			
		||||
    long v6 = strtol("0xA",  NULL, 0);
 | 
			
		||||
    long v7 = strtol("junk", NULL, 0);
 | 
			
		||||
    return 0;
 | 
			
		||||
}
 | 
			
		||||
    double v1 = strtod("  -0.0000000123junk", NULL);
 | 
			
		||||
    double v2 = strtod("junk", NULL);
 | 
			
		||||
}
 | 
			
		||||
		Loading…
	
		Reference in New Issue