use based functions from ryuu instead of ryuu itself, also fix some bugs

This commit is contained in:
bumbread 2022-07-20 11:41:24 +11:00
parent f94ef2da9e
commit 5e0d4ae8b7
7 changed files with 253 additions and 56 deletions

3
.gitmodules vendored
View File

@ -1,3 +1,6 @@
[submodule "unicope"] [submodule "unicope"]
path = unicope path = unicope
url = https://github.com/bumbread/unicope.git url = https://github.com/bumbread/unicope.git
[submodule "fdec64"]
path = fdec64
url = https://github.com/bumbread/fdec64.git

View File

@ -25,8 +25,8 @@ for arg in sys.argv[1:]:
sys.exit(0) sys.exit(0)
# Build dependencies rq # Build dependencies rq
if not Path("ryu/ryu.lib").exists(): if not Path("fdec64/fdec64.lib").exists():
os.chdir('ryu') os.chdir('fdec64')
runpy.run_path(path_name='bake.py') runpy.run_path(path_name='bake.py')
os.chdir('..') os.chdir('..')
@ -44,7 +44,7 @@ do_cuik = False
inc_folders = [ inc_folders = [
'inc', 'inc',
'unicope/inc', 'unicope/inc',
'ryu', 'fdec64',
] ]
definitions = [ definitions = [
@ -99,7 +99,7 @@ def nasm_compile(file_name):
#-----------------------------------------------------------------------------# #-----------------------------------------------------------------------------#
# Compile the platform-independent part # Compile the platform-independent part
obj_paths = ['ryu/ryu.lib', 'unicope/unicope.lib'] obj_paths = ['fdec64/fdec64.lib', 'unicope/unicope.lib']
compile_map = {} compile_map = {}
compile_map['.asm'] = nasm_compile compile_map['.asm'] = nasm_compile

1
fdec64 Submodule

@ -0,0 +1 @@
Subproject commit ecba3cda9a9db63185d51d527012f82a509e03cd

1
ryu

@ -1 +0,0 @@
Subproject commit bfc7d0b020e34e5c32e9ffbc94c0abe5e8559d42

View File

@ -9,7 +9,7 @@
#include <uchar.h> #include <uchar.h>
#include <wctype.h> #include <wctype.h>
#include <ryu/ryu.h> #include <fdec64.h>
typedef int (pfx(cbfn))(void *ctx, ctype ch); typedef int (pfx(cbfn))(void *ctx, ctype ch);
@ -267,13 +267,25 @@ static int pfx(vprintfcb)(
int P = prec; int P = prec;
if(!(flags & FLAG_PREC)) P = 6; if(!(flags & FLAG_PREC)) P = 6;
if(prec == 0) P = 1; if(prec == 0) P = 1;
int class = fpclassify(value);
int64_t E;
{
union { union {
uint64_t bits; uint64_t bits;
double value; double value;
} _ = {.value = value}; } _ = {.value = value};
uint64_t bits = _.bits; uint64_t bits = _.bits;
int E = (int)((bits >> 52) & 0x7ff) - 1023; uint64_t neg = bits >> 63;
int class = fpclassify(value); int64_t e2 = (int64_t)((bits >> 52) & ((1<<11)-1));
int64_t m2 = bits & ((UINT64_C(1)<<52)-1);
if(class == FP_ZERO) {
E = 0;
}
else {
fdec64 f = dtofdec64(m2, e2);
E = f.exponent;
}
}
if(class == FP_SUBNORMAL || class == FP_ZERO) { if(class == FP_SUBNORMAL || class == FP_ZERO) {
E = 0; E = 0;
} }
@ -645,12 +657,8 @@ static inline int pfx(_dtoh)(
out((class == FP_SUBNORMAL || class == FP_ZERO)? '0' : '1'); out((class == FP_SUBNORMAL || class == FP_ZERO)? '0' : '1');
// Print decimal point // Print decimal point
if(decimal_point_n) out('.'); if(decimal_point_n) out('.');
// Print precision padding int digs = mant_digits_n < prec? mant_digits_n : prec;
for(int i = mant_digits_n; i < prec; ++i) { for(int i = 0; i != digs; ++i) {
out('0');
}
if(prec < mant_digits_n) mant_digits_n = prec;
for(int i = 0; i != mant_digits_n; ++i) {
int bit = 52 - 4 - i; int bit = 52 - 4 - i;
int digit = (int)((mant >> bit) & 0xf); int digit = (int)((mant >> bit) & 0xf);
ctype ch; ctype ch;
@ -661,6 +669,10 @@ static inline int pfx(_dtoh)(
else ch = digit+'a'-10; else ch = digit+'a'-10;
out(ch); out(ch);
} }
// Print precision padding
for(int i = mant_digits_n; i < prec; ++i) {
out('0');
}
// Print the exponent part // Print the exponent part
out((flags & FLAG_UPPER)? 'P' : 'p'); out((flags & FLAG_UPPER)? 'P' : 'p');
out(exp_sign); out(exp_sign);
@ -687,24 +699,113 @@ static inline int pfx(_dtoa)(
if(class == FP_INFINITE || class == FP_NAN) { if(class == FP_INFINITE || class == FP_NAN) {
return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags); return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags);
} }
// This guy does memory allocation which makes it pretty cringe // Disassemble the float into parts
if(!(flags & FLAG_PREC)) prec = 6; int64_t exp;
char *buf = d2fixed(value, prec); int64_t mant;
int len = (int)strlen(buf); {
int pad = width - len; union {
// Left pad uint64_t bits;
double value;
} _ = {.value = value};
uint64_t bits = _.bits;
uint64_t neg = bits >> 63;
int64_t e2 = (int64_t)((bits >> 52) & ((1<<11)-1));
int64_t m2 = bits & ((UINT64_C(1)<<52)-1);
if(class == FP_ZERO) {
mant = 0;
exp = 0;
}
else {
fdec64 f = dtofdec64(m2, e2);
mant = f.mantissa;
exp = f.exponent;
}
}
// Figure out how many digits does mantissa take up (mant_digits_n)
// and the number of digits after decimal point (prec)
// and the number of digits before decimal point (while_digits_n)
static ctype mant_buf[64] = {0};
int whole_digits_n;
int mant_digits_n = 0;
{
int64_t m = mant;
do {
mant_buf[mant_digits_n++] = m % 10 + '0';
m /= 10;
} while(m != 0);
}
if((flags & FLAG_PREC) == 0) {
prec = 6;
}
whole_digits_n = mant_digits_n + exp;
if(whole_digits_n <= 0) whole_digits_n = 1;
// Figure out how many symbols decimal point takes up (0 or 1)
int decimal_point_n = 1;
if(prec == 0) {
decimal_point_n = 0;
if(flags & FLAG_HASH) {
decimal_point_n = 1;
}
}
// Figure out sign symbol and number of chars it takes up (0 or 1)
int sign_n = 0;
ctype sign_ch;
if(value < 0) {
sign_n = 1;
sign_ch = '-';
}
else if(flags & FLAG_PLUS) {
sign_n = 1;
sign_ch = '+';
}
else if(flags & FLAG_SPACE) {
sign_n = 1;
sign_ch = ' ';
}
// Figure out the width of the number
int significand_width = whole_digits_n + decimal_point_n + prec;
int n_width = sign_n + significand_width;
// Figure out width-padding required
int pad = 0;
if(width > n_width) pad = width - n_width;
// Print width left-pad if it's made out of space
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) { if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' '); out(' ');
} }
{ // Print sign if there
char *str = buf; if(sign_n)
while(*str) { out(sign_ch);
out(*str); // Print width left-pad if it's made out of zero
++str; if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad-- > 0) {
out('0');
} }
// Print whole part
while(whole_digits_n--) {
if(-exp >= mant_digits_n) {
out('0');
} }
free(buf); else {
// Right pad out(mant_buf[--mant_digits_n]);
}
++exp;
}
// Print decimal point
if(decimal_point_n) out('.');
// Print fractional part that's made out of digits
int prec_digs = prec - mant_digits_n;
while(mant_digits_n) {
if(-exp >= mant_digits_n) {
out('0');
}
else {
out(mant_buf[--mant_digits_n]);
}
++exp;
}
while(prec_digs-- > 0) {
out('0');
}
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) { if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' '); out(' ');
} }
@ -724,24 +825,122 @@ static inline int pfx(_etoa)(
if(class == FP_INFINITE || class == FP_NAN) { if(class == FP_INFINITE || class == FP_NAN) {
return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags); return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags);
} }
// This guy does memory allocation which makes it pretty cringe // Disassemble the float into parts
if(!(flags & FLAG_PREC)) prec = 6; int64_t exp;
char *buf = d2exp(value, prec); int64_t mant;
int len = (int)strlen(buf); {
int pad = width - len; union {
// Left pad uint64_t bits;
double value;
} _ = {.value = value};
uint64_t bits = _.bits;
uint64_t neg = bits >> 63;
int64_t e2 = (int64_t)((bits >> 52) & ((1<<11)-1));
int64_t m2 = bits & ((UINT64_C(1)<<52)-1);
if(class == FP_ZERO) {
mant = 0;
exp = 0;
}
else {
fdec64 f = dtofdec64(m2, e2);
mant = f.mantissa;
exp = f.exponent;
}
}
// Figure out how many digits does mantissa take up (mant_digits_n)
// and the number of digits after decimal point (prec)
static ctype mant_buf[64] = {0};
int mant_digits_n = 0;
{
int64_t m = mant;
do {
mant_buf[mant_digits_n++] = m % 10 + '0';
m /= 10;
} while(m != 0);
}
mant_digits_n -= 1;
// Need to adjust exponent based on the amount of digits in the mantissa
exp += mant_digits_n;
if((flags & FLAG_PREC) == 0) {
prec = 6;
}
// Figure out how many symbols decimal point takes up (0 or 1)
int decimal_point_n = 1;
if(prec == 0) {
decimal_point_n = 0;
if(flags & FLAG_HASH) {
decimal_point_n = 1;
}
}
// Figure out how many digits exponent take up and it's sign
// also save exponent digits to a buffer starting from LSD
static ctype exp_buf[64] = {0};
int exp_digits_n = 0;
ctype exp_sign;
if(exp < 0) {
exp_sign = '-';
exp = -exp;
}
else {
exp_sign = '+';
}
{
int64_t e = exp;
do {
exp_buf[exp_digits_n++] = e % 10 + '0';
e /= 10;
} while(e != 0);
}
// Figure out sign symbol and number of chars it takes up (0 or 1)
int sign_n = 0;
ctype sign_ch;
if(value < 0) {
sign_n = 1;
sign_ch = '-';
}
else if(flags & FLAG_PLUS) {
sign_n = 1;
sign_ch = '+';
}
else if(flags & FLAG_SPACE) {
sign_n = 1;
sign_ch = ' ';
}
// Figure out the width of the number
int significand_width = 1 + decimal_point_n + prec;
int exp_part_width = 2 /*e+-*/ + exp_digits_n;
int n_width = sign_n + significand_width + exp_part_width;
// Figure out width-padding required
int pad = 0;
if(width > n_width) pad = width - n_width;
// Print width left-pad if it's made out of space
if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) { if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) {
out(' '); out(' ');
} }
{ // Print sign if there
char *str = buf; if(sign_n)
while(*str) { out(sign_ch);
out(*str); // Print width left-pad if it's made out of zero
++str; if(!(flags & FLAG_LEFT) && (flags & FLAG_ZERO)) while(pad-- > 0) {
out('0');
} }
// Print whole part
out(mant_buf[mant_digits_n]);
// Print decimal point
if(decimal_point_n) out('.');
// Print precision padding
for(int i = mant_digits_n; i < prec; ++i) {
out('0');
} }
free(buf); if(prec < mant_digits_n) mant_digits_n = prec;
// Right pad while(mant_digits_n--)
out(mant_buf[mant_digits_n]);
// Print the exponent part
out((flags & FLAG_UPPER)? 'E' : 'e');
out(exp_sign);
while(exp_digits_n--)
out(exp_buf[exp_digits_n]);
// Print right-pad
if(flags & FLAG_LEFT) while(pad-- > 0) { if(flags & FLAG_LEFT) while(pad-- > 0) {
out(' '); out(' ');
} }

View File

@ -4,13 +4,10 @@
#include <limits.h> #include <limits.h>
int main() { int main() {
static char str[] = "XYabcZW"; printf("%g\n", 0.0);
printf("|1234567890123|\n"); printf("%g\n", 0.00000031415);
printf("|%13s|\n", str); printf("%g\n", 3.1415);
printf("|%-13.9s|\n", str); printf("%g\n", 31.415);
printf("|%13.10s|\n", str); printf("%g\n", 314.15);
printf("|%13.11s|\n", str);
printf("|%13.15s|\n", &str[2]);
printf("|%13c|\n", str[5]);
return 0; return 0;
} }

2
todo
View File

@ -32,8 +32,6 @@ stdio.h:
are flushed after main() returns. I wonder if only remembering the files are flushed after main() returns. I wonder if only remembering the files
with a buffer would increase performance. with a buffer would increase performance.
* Formatted scan * Formatted scan
* The float printing should include width specifiers
* %g should use decimal exponent
* %s precision should specify how much characters to *write* * %s precision should specify how much characters to *write*
stdlib.h: stdlib.h: