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 <stdbool.h>
|
||||||
#include <limits.h>
|
#include <limits.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
// TODO: strto*: locale-based parsing for integers
|
// TODO: strto*: locale-based parsing
|
||||||
// TODO: i made a function that parses longs and i'm fucken
|
// TODO: correctly rounded base 16 floats parsing
|
||||||
// tired. someone make float parsing :kekw:
|
|
||||||
|
|
||||||
// Call me weak if you want but I'm actually too lazy to type
|
// 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.
|
// 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;
|
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
|
// Called only when isbase(c, base) for some base in range
|
||||||
static long todigitl(int c) {
|
static long todigit(int c) {
|
||||||
int val;
|
int val;
|
||||||
if(isdigit(c)) {
|
if(isdigit(c)) {
|
||||||
val = c-'0';
|
val = c-'0';
|
||||||
|
@ -51,7 +63,7 @@ static long todigitl(int c) {
|
||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
static intull strto_generic(
|
static intull strtoi_generic(
|
||||||
const char *restrict nptr,
|
const char *restrict nptr,
|
||||||
char **restrict endptr,
|
char **restrict endptr,
|
||||||
int inbase,
|
int inbase,
|
||||||
|
@ -89,7 +101,7 @@ static intull strto_generic(
|
||||||
}
|
}
|
||||||
// See if we need to parse base in C-like format
|
// See if we need to parse base in C-like format
|
||||||
// then set the base accordingly
|
// then set the base accordingly
|
||||||
if(*str == '0' && (*(str+1) == 'x' || *(str+1) == 'X')) {
|
if(strprefix_i(str, "0X")) {
|
||||||
++str;
|
++str;
|
||||||
if(base == 16 || base == 0) {
|
if(base == 16 || base == 0) {
|
||||||
++str;
|
++str;
|
||||||
|
@ -109,7 +121,7 @@ static intull strto_generic(
|
||||||
// Parse the string of digits in the given base. If the value
|
// Parse the string of digits in the given base. If the value
|
||||||
// exceeds abs(int_min) we exit with range error.
|
// exceeds abs(int_min) we exit with range error.
|
||||||
while(isbase(*str, (int)base)) {
|
while(isbase(*str, (int)base)) {
|
||||||
intull digit = (intull)todigitl(*str);
|
intull digit = (intull)todigit(*str);
|
||||||
if(value > (int_abs_max - digit)/base) {
|
if(value > (int_abs_max - digit)/base) {
|
||||||
goto error_out_of_range;
|
goto error_out_of_range;
|
||||||
}
|
}
|
||||||
|
@ -152,10 +164,126 @@ finish:
|
||||||
return value;
|
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) {
|
intl strtol(const char *restrict nptr, char **restrict endptr, int base) {
|
||||||
intull int_max = (intull)LONG_MAX;
|
intull int_max = (intull)LONG_MAX;
|
||||||
intl coef;
|
intl coef;
|
||||||
intull modulo = strto_generic(nptr, endptr, base, &coef, int_max);
|
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||||
intl value;
|
intl value;
|
||||||
if(modulo == int_max) {
|
if(modulo == int_max) {
|
||||||
value = LONG_MIN;
|
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) {
|
intll strtoll(const char *restrict nptr, char **restrict endptr, int base) {
|
||||||
intull int_max = (intull)LLONG_MAX;
|
intull int_max = (intull)LLONG_MAX;
|
||||||
intl coef;
|
intl coef;
|
||||||
intull modulo = strto_generic(nptr, endptr, base, &coef, int_max);
|
intull modulo = strtoi_generic(nptr, endptr, base, &coef, int_max);
|
||||||
intll value;
|
intll value;
|
||||||
if(modulo == int_max) {
|
if(modulo == int_max) {
|
||||||
value = LLONG_MIN;
|
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) {
|
intul strtoul(const char *restrict nptr, char **restrict endptr, int base) {
|
||||||
intull int_max = (intull)ULONG_MAX;
|
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;
|
return (intul)value;
|
||||||
}
|
}
|
||||||
|
|
||||||
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
|
intull strtoull(const char *restrict nptr, char **restrict endptr, int base) {
|
||||||
intull int_max = (intull)ULLONG_MAX;
|
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) {
|
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) {
|
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) {
|
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) {
|
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_INFINITE 1
|
||||||
#define FP_NAN 2
|
#define FP_NAN 2
|
||||||
|
|
||||||
FP_INFINITE
|
//FP_INFINITE
|
||||||
FP_NAN
|
//FP_NAN
|
||||||
FP_NORMAL
|
//FP_NORMAL
|
||||||
FP_SUBNORMAL
|
//FP_SUBNORMAL
|
||||||
FP_ZERO
|
//FP_ZERO
|
||||||
#define FP_FAST_FMA 1
|
#define FP_FAST_FMA 1
|
||||||
#define FP_FAST_FMAF 1
|
#define FP_FAST_FMAF 1
|
||||||
#define FP_FAST_FMAL 1
|
#define FP_FAST_FMAL 1
|
||||||
|
@ -39,8 +39,11 @@ FP_ZERO
|
||||||
|
|
||||||
// TODO: implement this
|
// TODO: implement this
|
||||||
#define fpclassify(x) 0
|
#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 isnan(x) 0
|
||||||
#define isnormal(x) 0
|
#define isnormal(x) 0
|
||||||
#define signbit(x) 0
|
#define signbit(x) 0
|
||||||
|
|
53
test/test.c
53
test/test.c
|
@ -1,44 +1,27 @@
|
||||||
#include <assert.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
int main(int argc, char** argv) {
|
int main(void)
|
||||||
const char *p = "10 200000000000000000000000000000 30 -40 junk";
|
{
|
||||||
// printf("Parsing '%s':\n", p);
|
double v0 = strtod("0X1.BC70A3D70A3D7P+6", NULL);
|
||||||
|
|
||||||
|
// parsing with error handling
|
||||||
|
const char *p = "111.11 -2.22 Nan nan(2) inF 0X1.BC70A3D70A3D7P+6 1.18973e+4932zzz";
|
||||||
|
|
||||||
for (;;)
|
|
||||||
{
|
|
||||||
// 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;
|
char *end;
|
||||||
const long i = strtol(p, &end, 10);
|
for (double f = strtod(p, &end); p != end; f = strtod(p, &end))
|
||||||
if (p == end)
|
{
|
||||||
break;
|
// printf("'%.*s' -> ", (int)(end-p), p);
|
||||||
|
|
||||||
const bool range_error = errno == ERANGE;
|
|
||||||
// printf("Extracted '%.*s', strtol returned %ld.", (int)(end-p), p, i);
|
|
||||||
p = end;
|
p = end;
|
||||||
|
if (errno == ERANGE){
|
||||||
// if (range_error)
|
// printf("range error, got ");
|
||||||
// printf(" Range error occurred.");
|
errno = 0;
|
||||||
|
}
|
||||||
// putchar('\n');
|
// printf("%f\n", f);
|
||||||
}
|
}
|
||||||
|
|
||||||
// printf("Unextracted leftover: '%s'\n\n", p);
|
|
||||||
|
|
||||||
// parsing without error handling
|
// parsing without error handling
|
||||||
long v1 = strtol("1010", NULL, 2);
|
double v1 = strtod(" -0.0000000123junk", NULL);
|
||||||
long v2 = strtol("12", NULL, 8);
|
double v2 = strtod("junk", NULL);
|
||||||
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;
|
|
||||||
}
|
}
|
Loading…
Reference in New Issue