bad floats for printf

This commit is contained in:
bumbread 2022-07-19 08:27:37 +11:00
parent e96c840ce4
commit 8f0bf83f0b
11 changed files with 168 additions and 23 deletions

3
.gitmodules vendored
View File

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

25
bake.py
View File

@ -1,9 +1,29 @@
import os import os
import sys
import subprocess import subprocess
import runpy import runpy
from pathlib import Path 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 # Build dependencies rq
if not Path("ryu/ryu.lib").exists(): if not Path("ryu/ryu.lib").exists():
os.chdir('ryu') os.chdir('ryu')
@ -23,7 +43,8 @@ do_cuik = False
inc_folders = [ inc_folders = [
'inc', 'inc',
os.path.join('unicope', 'inc'), 'unicope/inc',
'ryu',
] ]
definitions = [ definitions = [
@ -101,5 +122,5 @@ compile(os.path.normpath('src/code'), compile_map)
for dir, _, f in os.walk('bin'): for dir, _, f in os.walk('bin'):
if len(f) != 0: if len(f) != 0:
obj_paths.append(os.path.join(dir, '*.obj')) 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') print('*.obj => ciabatta.lib')

View File

@ -3,7 +3,11 @@
#include <stdlib.h> #include <stdlib.h>
#include <inttypes.h> #include <inttypes.h>
#include <limits.h> #include <limits.h>
#include <string.h>
#include <math.h> #include <math.h>
#include <ctype.h>
#include <ryu/ryu.h>
typedef int (pfx(cbfn))(void *ctx, ctype ch); typedef int (pfx(cbfn))(void *ctx, ctype ch);
@ -42,6 +46,24 @@ static inline int pfx(_dtoh)(
int width, int width,
int flags 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)( static inline int pfx(_infnantoa)(
int w, int w,
void *ctx, void *ctx,
@ -229,7 +251,38 @@ static int pfx(vprintfcb)(
case 'F': case 'F':
case 'g': case 'g':
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; break;
} }
} }
@ -516,4 +569,78 @@ static inline int pfx(_dtoh)(
return w; 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 #undef out

View File

@ -9,9 +9,9 @@ dname = os.path.dirname(abspath)
os.chdir(dname) os.chdir(dname)
data=[ data=[
('cordic_dataf.c', 'float', 'f', 32), ('cordic_dataf.h', 'float', 'f', 32),
('cordic_data.c', 'double', '', 64), ('cordic_data.h', 'double', '', 64),
('cordic_datal.c', 'long double', 'l', 64), ('cordic_datal.h', 'long double', 'l', 64),
] ]
for f in data: for f in data:

View File

@ -14,21 +14,21 @@ static double LOG2E = 1.442695040888963407359924681001892;
#define ftype float #define ftype float
#define suffix(name) name ## f #define suffix(name) name ## f
#include "cordic/cordic_dataf.c" #include "cordic/cordic_dataf.h"
#include "gen_math.h" #include "gen_math.h"
#undef ftype #undef ftype
#undef suffix #undef suffix
#define ftype double #define ftype double
#define suffix(name) name #define suffix(name) name
#include "cordic/cordic_data.c" #include "cordic/cordic_data.h"
#include "gen_math.h" #include "gen_math.h"
#undef ftype #undef ftype
#undef suffix #undef suffix
#define ftype long double #define ftype long double
#define suffix(name) name ## l #define suffix(name) name ## l
#include "cordic/cordic_datal.c" #include "cordic/cordic_datal.h"
#include "gen_math.h" #include "gen_math.h"
#undef ftype #undef ftype
#undef suffix #undef suffix

View File

@ -64,7 +64,8 @@ void free(void *ptr) {
} }
void *malloc(size_t size) { 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) { void *realloc(void *ptr, size_t size) {

View File

@ -4,14 +4,7 @@
#include <limits.h> #include <limits.h>
int main() { int main() {
printf("%a\n", 0.0); printf("%g\n", 1.2345e+10);
printf("%a\n", 2.0); printf("%g\n", 123.45);
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);
return 0; return 0;
} }

8
todo
View File

@ -31,15 +31,21 @@ stdio.h:
* The only reason to keep a linked list of all streams is to make sure they * 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 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 print, scan * Formatted scan
* The float printing should include width specifiers
* %g should use decimal exponent
stdlib.h: stdlib.h:
* Strtod base 16 must be correctly rounded * Strtod base 16 must be correctly rounded
* Multibyte string functions * Multibyte string functions
* Better PRNG * Better PRNG
* Fix aligned_malloc
threads.h: threads.h:
* TODO: add todo items * TODO: add todo items
wchar.h: wchar.h:
* Basically everything * Basically everything
entry:
* Pretty sure there is a bug in counting wide chars for parsing argv