shithub: mc

Download patch

ref: b42a202d2ca1cae5c112e1cfd881976c944a5261
parent: b1fe880775f7019fc3169ea31444cc59d9b232fa
author: Ori Bernstein <[email protected]>
date: Tue Sep 16 21:40:38 EDT 2014

Float formatting finally implemented.

--- a/libstd/Makefile
+++ b/libstd/Makefile
@@ -15,6 +15,7 @@
     extremum.myr \
     floatbits.myr \
     fmt.myr \
+    floatfmt.myr \
     hashfuncs.myr \
     hasprefix.myr \
     hassuffix.myr \
--- a/libstd/bigint.myr
+++ b/libstd/bigint.myr
@@ -3,7 +3,6 @@
 use "cmp.use"
 use "die.use"
 use "extremum.use"
-use "fmt.use"
 use "hasprefix.use"
 use "option.use"
 use "slcp.use"
@@ -144,9 +143,9 @@
 	while !bigiszero(val)
 		(v, rem) = bigdivmod(val, b)
 		if rem.dig.len > 0
-			n += bfmt(buf[n:], "%c", digitchars[rem.dig[0]])
+			n += encode(buf[n:], digitchars[rem.dig[0]])
 		else
-			n += bfmt(buf[n:], "0")
+			n += encode(buf[n:], '0')
 		;;
 		bigfree(val)
 		bigfree(rem)
--- a/libstd/floatbits.myr
+++ b/libstd/floatbits.myr
@@ -16,7 +16,7 @@
 	var bits, isneg, mant, exp
 
 	bits = float64bits(flt)
-	isneg = (bits >> 63) == 0  	/* msb is sign bit */
+	isneg = (bits >> 63) != 0  	/* msb is sign bit */
 	exp = (bits >> 52) & 0x7ff 	/* exp is in bits [52..63] */
 	mant = bits & ((1l << 52) - 1) /* msb is in bits [..51] */
 
--- /dev/null
+++ b/libstd/fltfmt.myr
@@ -1,0 +1,200 @@
+use "bigint.use"
+
+pkg std =
+	const float64bfmt	: 
+	const float32bfmt	: 
+
+const Dblbias = 1023
+const Fltbias
+
+const fltbfmt = {buf, dbl
+	var sign, exp, mant
+
+	(sign, mant, exp) = float64explode(dbl)
+	-> dragon4(buf, sign, mant, (exp - 52) castto(int64), DblBias, `Normal, -32)
+}
+
+type cutmode = union
+	`Normal
+	`Absolute
+	`Relative
+;;
+
+/*
+buf: output buffer
+e: exponent
+p: precision
+f: mantissa
+
+floating value: x = f^(e - p)
+*/
+const dragon4 = {buf, isneg, f, e, p, mode, cutoff
+	var r, s, t, u, v
+	var udig
+	var mm, mp	/* margins above and below */
+	var roundup
+	var low, high
+	var k : int, n
+
+	put("encoding... isneg = %t, f = %xl, exp = %l, p = %l\n", isneg, f, e, p)
+	/* if we have zero for the mantissa, we can return early */
+	n = 0
+	if isneg
+		n += bfmt(buf, "-")
+	;;
+	if f == 0
+		n += bfmt(buf, "0.0")
+		-> buf[:n]
+	;;
+
+	/* initialize */
+	roundup = false
+	r = mkbigint(f)
+	r = bigshli(r, max(e - p, 0))
+	s = bigshli(mkbigint(1), max(0, -(e - p)))
+	mm = bigshli(mkbigint(1), max((e - p), 0))
+	mp = bigdup(mm)
+	put("r = %s, s = %s, mm = %s, mp = %s\n", \
+		bigfmt(r, 0), bigfmt(s, 0), bigfmt(mm, 0), bigfmt(mp, 0))
+
+	/* fixup: unequal gaps */
+	t = mkbigint(1)
+	bigshli(t, p - 1)
+	if bigeqi(t, f)
+		bigshli(mp, 1)
+		bigshli(r, 1)
+		bigshli(s, 1)
+	;;
+	bigfree(t)
+
+	put("r = %s, s = %s, mm = %s, mp = %s\n", \
+		bigfmt(r, 0), bigfmt(s, 0), bigfmt(mm, 0), bigfmt(mp, 0))
+
+	k = 0
+	while true
+		/* r < ceil(s/b) */
+		t = bigdup(s)
+		bigaddi(t, 9)
+		bigdivi(t, 10)
+		match bigcmp(r, t)
+		| `Before:
+			k--
+			bigmuli(r, 10)
+			bigmuli(mm, 10)
+			bigmuli(mp, 10)
+		| _:
+			bigfree(t)
+			break
+		;;
+		bigfree(t)
+	;;
+	put("r = %s, s = %s, mm = %s, mp = %s\n", \
+		bigfmt(r, 0), bigfmt(s, 0), bigfmt(mm, 0), bigfmt(mp, 0))
+
+	t = bigdup(r)
+	bigshli(t, 1)
+	bigadd(t, mp)
+	while true
+		u = bigdup(s)
+		bigshli(u, 1)
+		put("t = 2*r + mp = %s, u = 2*s = %s\n", bigfmt(t, 0), bigfmt(u, 0))
+		put("s = %s\n", bigfmt(s, 0))
+		match bigcmp(t, u)
+		| `Before:
+			bigfree(u)
+			break
+		| _:
+			k++
+			bigmuli(s, 10)
+			bigfree(u)
+		;;
+	;;
+	cutoff = k - buf.len - 1
+	bigfree(t)
+	put("r = %s, s = %s, mm = %s, mp = %s, cutoff = %i\n", \
+		bigfmt(r, 0), bigfmt(s, 0), bigfmt(mm, 0), bigfmt(mp, 0), \ 
+		cutoff)
+
+	if k <= 0
+		n += bfmt(buf[n:], "0.")
+	;;
+	while true
+		k--
+		bigmuli(r, 10)
+		u = bigdup(r);
+		bigdiv(u, s)
+
+		bigmod(r, s)
+		bigmuli(mm, 10)
+		bigmuli(mp, 10)
+
+		low = false
+		t = bigdup(r)
+		bigshli(t, 1)
+		put("t = %s, mm = %s\n", bigfmt(t, 0), bigfmt(mm, 0))
+		match bigcmp(t, mm)
+		| `Before:	low = true
+		;;
+		bigfree(t)
+		
+		v = bigdup(r)
+		bigshli(v, 1)
+		t = bigdup(s)
+		bigshli(t, 1)
+		bigsub(t, mp)
+		match bigcmp(v, t)
+		| `After: high = true
+		| `Equal: high = roundup
+		| `Before: high = false
+		;;
+		bigfree(v)
+		bigfree(t)
+		if low || high || k == cutoff
+			put("low = %t, high = %t, k == cutoff = %t\n", \
+				low, high, k == cutoff)
+			break
+		;;
+		n += format(buf[n:], lowdig(u), k)
+		bigfree(u)
+	;;
+
+	/* format the last digit */
+	udig = lowdig(u)
+	if low && !high
+		n += format(buf[n:], udig, k)
+	elif high && !low
+		n += format(buf[n:], udig + 1, k)
+	else
+		bigmuli(r, 2)
+		match bigcmp(r, s)
+		| `Before:	n += format(buf[n:], udig, k)
+		| `Equal:	n += format(buf[n:], udig, k)
+		| `After:	n += format(buf[n:], udig + 1, k)
+		;;
+	;;
+	put("n = %i\n", n)
+	-> buf[:n]
+}
+
+const lowdig = {u
+	if u.dig.len > 0
+		-> u.dig[0]
+	;;
+	-> 0
+}
+
+const format = {buf, d, k
+	const dig = "0123456789"
+	var n, i
+
+	n = 0
+	if k == 0
+		n += encode(buf[n:], '.')
+	elif k < 0
+		for i = 0; i < -k; i++
+			n += encode(buf[n:], '0')
+		;;
+	;;
+	buf[n++] = dig[d]
+	-> n
+}
--- a/libstd/fmt.myr
+++ b/libstd/fmt.myr
@@ -6,6 +6,7 @@
 use "varargs.use"
 use "extremum.use"
 use "chartype.use"
+use "floatfmt.use"
 
 /*
   printf-like functions. These use a different syntax from the C printf,
@@ -152,6 +153,7 @@
 /* formats a string of text as specified by 'fmt' into 'buf',
    using a valist for the arguments */
 const bfmtv = {buf, fmt, ap
+	var b
 	var c
 	var n
 	var padto
@@ -217,7 +219,9 @@
 				n += boolfmt(buf[n:], t_val, padto, padfill)
 			| 'f':
 				(f_val, ap) = vanext(ap)
-				n += floatfmt(buf[n:], f_val, 0, 0, padto, padfill)
+				b = buf[n:]
+				/* FIXME(ori): bug, b[n:].len fails since b[n:] isn't an lval */
+				n += float64bfmt(buf[n:], f_val, 0, b.len)
 			/* FIXME: float casts are currently broken
 			| 'F':
 				(F_val, ap) = vanext(ap)
@@ -301,36 +305,5 @@
 		s = "false"
 	;;
 	-> strfmt(buf, s, padto, padfill)
-}
-
-/*
- buf: the output buffer.
- val: the value to format, in float64 format.
- mode: the truncation mode.
- 	0 => print until precision exhausted.
-	1 => print until precision exhausted or maxdigits produced.
-	2 => print until maxdigits produced, paddding with zeros.
- */
-
-const floatfmt = {buf, val, mode, maxdigits, padto, padfill
-	var i
-	var n
-	/*
-	var isneg
-	*/
-	/*var b, e, f*/
-
-	/* handle 0 specially to avoid special cases */
-	if val == 0.0
-		n = strfmt(buf, "0.0", padto, padfill)
-		if mode == 0 && maxdigits > 2
-			for i = 1; i < maxdigits; i++
-				n += strfmt(buf[n:], "0", padto, padfill)
-			;;
-		;;
-		-> n
-	;;
-
-	-> strfmt(buf, "floats not implemented", padto, padfill)
 }
 
--- a/libstd/option.myr
+++ b/libstd/option.myr
@@ -1,7 +1,3 @@
-use "types.use"
-use "fmt.use"
-use "varargs.use"
-
 pkg std =
 	type option(@a) = union
 		`Some @a
--- a/libstd/slpush.myr
+++ b/libstd/slpush.myr
@@ -1,6 +1,5 @@
 use "types.use"
 use "alloc.use"
-use "fmt.use"
 
 pkg std =
 	generic slpush	: (sl : @a[:], elt : @a	-> @a[:])
--- a/parse/tok.c
+++ b/parse/tok.c
@@ -630,7 +630,7 @@
     /* because we allow '_' in numbers, and strtod/stroull don't, we
      * need a buffer that holds the number without '_'.
      */
-    char buf[128];
+    char buf[2048];
     size_t nbuf;
 
     t = NULL;