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;