From 8f0bf83f0b87bbab0ae8de8a9dafa34ad41baab3 Mon Sep 17 00:00:00 2001 From: bumbread Date: Tue, 19 Jul 2022 08:27:37 +1100 Subject: [PATCH] bad floats for printf --- .gitmodules | 3 - bake.py | 25 +++- src/code/fmt/gen_fmt.h | 129 +++++++++++++++++- .../cordic/{cordic_data.c => cordic_data.h} | 0 .../cordic/{cordic_dataf.c => cordic_dataf.h} | 0 .../cordic/{cordic_datal.c => cordic_datal.h} | 0 src/code/math/cordic/maketab.py | 6 +- src/code/math/gen_math.c | 6 +- src/win/win_heap.c | 3 +- test/test_printf.c | 11 +- todo | 8 +- 11 files changed, 168 insertions(+), 23 deletions(-) rename src/code/math/cordic/{cordic_data.c => cordic_data.h} (100%) rename src/code/math/cordic/{cordic_dataf.c => cordic_dataf.h} (100%) rename src/code/math/cordic/{cordic_datal.c => cordic_datal.h} (100%) diff --git a/.gitmodules b/.gitmodules index bb67b08..199449c 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "unicope"] path = unicope url = https://github.com/bumbread/unicope.git -[submodule "ryu"] - path = ryu - url = https://github.com/bumbread/ryu.git diff --git a/bake.py b/bake.py index 7c35ce6..09e9a77 100644 --- a/bake.py +++ b/bake.py @@ -1,9 +1,29 @@ import os +import sys import subprocess import runpy from pathlib import Path +for arg in sys.argv[1:]: + if arg == 'test': + test = os.getenv('test'); + if test == None: + test = 'assert' + test_file = 'test/test_' + test + '.c' + subprocess.run([ + 'clang', + test_file, + '-Iinc', + '-g', + '-luser32', + '-lkernel32', + '-lshell32', + '-lDbghelp', + '-lciabatta.lib', + ]) + sys.exit(0) + # Build dependencies rq if not Path("ryu/ryu.lib").exists(): os.chdir('ryu') @@ -23,7 +43,8 @@ do_cuik = False inc_folders = [ 'inc', - os.path.join('unicope', 'inc'), + 'unicope/inc', + 'ryu', ] definitions = [ @@ -101,5 +122,5 @@ compile(os.path.normpath('src/code'), compile_map) for dir, _, f in os.walk('bin'): if len(f) != 0: obj_paths.append(os.path.join(dir, '*.obj')) -subprocess.run(['llvm-ar', 'rc', 'ciabatta.lib'] + obj_paths) +subprocess.run(['lib', '/out:ciabatta.lib'] + obj_paths) print('*.obj => ciabatta.lib') \ No newline at end of file diff --git a/src/code/fmt/gen_fmt.h b/src/code/fmt/gen_fmt.h index 0ca9a95..81ce1a7 100644 --- a/src/code/fmt/gen_fmt.h +++ b/src/code/fmt/gen_fmt.h @@ -3,7 +3,11 @@ #include #include #include +#include #include +#include + +#include typedef int (pfx(cbfn))(void *ctx, ctype ch); @@ -42,6 +46,24 @@ static inline int pfx(_dtoh)( int width, int flags ); +static inline int pfx(_dtoa)( + int w, + void *ctx, + pfx(cbfn) cb, + double value, + int prec, + int width, + int flags +); +static inline int pfx(_etoa)( + int w, + void *ctx, + pfx(cbfn) cb, + double value, + int prec, + int width, + int flags +); static inline int pfx(_infnantoa)( int w, void *ctx, @@ -229,7 +251,38 @@ static int pfx(vprintfcb)( case 'F': case 'g': case 'G': - + if(*fmt == 'E' || *fmt == 'F' || *fmt == 'G') flags |= FLAG_UPPER; + char conv = tolower(*fmt); + ++fmt; + double value = va_arg(va, double); + if(conv == 'f') { + w = pfx(_dtoa)(w, ctx, cb, value, prec, width, flags); + } + else if(conv == 'e') { + w = pfx(_etoa)(w, ctx, cb, value, prec, width, flags); + } + else { + int P = prec; + if(!(flags & FLAG_PREC)) P = 6; + if(prec == 0) P = 1; + union { + uint64_t bits; + double value; + } _ = {.value = value}; + uint64_t bits = _.bits; + int E = (int)((bits >> 52) & 0x7ff) - 1023; + int class = fpclassify(value); + if(class == FP_SUBNORMAL || class == FP_ZERO) { + E = 0; + } + if(P > E && E >= -4) { + w = pfx(_dtoa)(w, ctx, cb, value, P-(E+1), width, flags); + } + else { + w = pfx(_etoa)(w, ctx, cb, value, P-1, width, flags); + } + } + if(w < 0) return -1; break; } } @@ -516,4 +569,78 @@ static inline int pfx(_dtoh)( return w; } +static inline int pfx(_dtoa)( + int w, + void *ctx, + pfx(cbfn) cb, + double value, + int prec, + int width, + int flags +) { + int class = fpclassify(value); + if(class == FP_INFINITE || class == FP_NAN) { + return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags); + } + // This guy does memory allocation which makes it pretty cringe + if(!(flags & FLAG_PREC)) prec = 6; + char *buf = d2fixed(value, prec); + int len = (int)strlen(buf); + int pad = width - len; + // Left pad + if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) { + out(' '); + } + { + char *str = buf; + while(*str) { + out(*str); + ++str; + } + } + free(buf); + // Right pad + if(flags & FLAG_LEFT) while(pad-- > 0) { + out(' '); + } + return w; +} + +static inline int pfx(_etoa)( + int w, + void *ctx, + pfx(cbfn) cb, + double value, + int prec, + int width, + int flags +) { + int class = fpclassify(value); + if(class == FP_INFINITE || class == FP_NAN) { + return pfx(_infnantoa)(w, ctx, cb, value, prec, width, flags); + } + // This guy does memory allocation which makes it pretty cringe + if(!(flags & FLAG_PREC)) prec = 6; + char *buf = d2exp(value, prec); + int len = (int)strlen(buf); + int pad = width - len; + // Left pad + if(!(flags & FLAG_LEFT) && !(flags & FLAG_ZERO)) while(pad-- > 0) { + out(' '); + } + { + char *str = buf; + while(*str) { + out(*str); + ++str; + } + } + free(buf); + // Right pad + if(flags & FLAG_LEFT) while(pad-- > 0) { + out(' '); + } + return w; +} + #undef out diff --git a/src/code/math/cordic/cordic_data.c b/src/code/math/cordic/cordic_data.h similarity index 100% rename from src/code/math/cordic/cordic_data.c rename to src/code/math/cordic/cordic_data.h diff --git a/src/code/math/cordic/cordic_dataf.c b/src/code/math/cordic/cordic_dataf.h similarity index 100% rename from src/code/math/cordic/cordic_dataf.c rename to src/code/math/cordic/cordic_dataf.h diff --git a/src/code/math/cordic/cordic_datal.c b/src/code/math/cordic/cordic_datal.h similarity index 100% rename from src/code/math/cordic/cordic_datal.c rename to src/code/math/cordic/cordic_datal.h diff --git a/src/code/math/cordic/maketab.py b/src/code/math/cordic/maketab.py index d46700e..055d754 100644 --- a/src/code/math/cordic/maketab.py +++ b/src/code/math/cordic/maketab.py @@ -9,9 +9,9 @@ dname = os.path.dirname(abspath) os.chdir(dname) data=[ - ('cordic_dataf.c', 'float', 'f', 32), - ('cordic_data.c', 'double', '', 64), - ('cordic_datal.c', 'long double', 'l', 64), + ('cordic_dataf.h', 'float', 'f', 32), + ('cordic_data.h', 'double', '', 64), + ('cordic_datal.h', 'long double', 'l', 64), ] for f in data: diff --git a/src/code/math/gen_math.c b/src/code/math/gen_math.c index 206d8cc..0ef25bb 100644 --- a/src/code/math/gen_math.c +++ b/src/code/math/gen_math.c @@ -14,21 +14,21 @@ static double LOG2E = 1.442695040888963407359924681001892; #define ftype float #define suffix(name) name ## f -#include "cordic/cordic_dataf.c" +#include "cordic/cordic_dataf.h" #include "gen_math.h" #undef ftype #undef suffix #define ftype double #define suffix(name) name -#include "cordic/cordic_data.c" +#include "cordic/cordic_data.h" #include "gen_math.h" #undef ftype #undef suffix #define ftype long double #define suffix(name) name ## l -#include "cordic/cordic_datal.c" +#include "cordic/cordic_datal.h" #include "gen_math.h" #undef ftype #undef suffix diff --git a/src/win/win_heap.c b/src/win/win_heap.c index ece3e54..28a67c6 100644 --- a/src/win/win_heap.c +++ b/src/win/win_heap.c @@ -64,7 +64,8 @@ void free(void *ptr) { } void *malloc(size_t size) { - return aligned_alloc(8, size); + if(size == 0) return NULL; + return HeapAlloc(heap_handle, 0, size); } void *realloc(void *ptr, size_t size) { diff --git a/test/test_printf.c b/test/test_printf.c index 134a57e..39afd6d 100644 --- a/test/test_printf.c +++ b/test/test_printf.c @@ -4,14 +4,7 @@ #include int main() { - printf("%a\n", 0.0); - printf("%a\n", 2.0); - printf("%#a\n", 128.0); - printf("%a\n", 128.0); - printf("%16a|\n", 128.0); - printf("%16.2a|\n", 128.0); - printf("%-16.2a|\n", 128.0); - printf("%016.2a|\n", 128.0); - printf("%.2A\n", 3.141592); + printf("%g\n", 1.2345e+10); + printf("%g\n", 123.45); return 0; } diff --git a/todo b/todo index 1215597..9833d1b 100644 --- a/todo +++ b/todo @@ -31,15 +31,21 @@ stdio.h: * The only reason to keep a linked list of all streams is to make sure they are flushed after main() returns. I wonder if only remembering the files with a buffer would increase performance. -* Formatted print, scan +* Formatted scan +* The float printing should include width specifiers +* %g should use decimal exponent stdlib.h: * Strtod base 16 must be correctly rounded * Multibyte string functions * Better PRNG +* Fix aligned_malloc threads.h: * TODO: add todo items wchar.h: * Basically everything + +entry: +* Pretty sure there is a bug in counting wide chars for parsing argv