ref: 5621e8b572b950f9ded3127078362a9617dcb375
dir: /libstd/fltfmt.myr/
use "bigint.use"
use "types.use"
use "fltbits.use"
use "extremum.use"
use "utf.use"
use "alloc.use"
use "slpush.use"
use "die.use"
pkg std =
pkglocal const flt64bfmt : (buf : byte[:], val : flt64, mode : int, precision : int -> size)
pkglocal const flt32bfmt : (buf : byte[:], val : flt32, mode : int, precision : int -> size)
;;
const Dblbias = 1023
const Fltbias = 127
const flt64bfmt = {buf, val, mode, precision
var isneg, exp, mant
(isneg, mant, exp) = flt64explode(val)
-> dragon4(buf, isneg, mant, (exp - 52) castto(int64), Dblbias, mode, precision)
}
const flt32bfmt = {buf, val, mode, precision
var isneg, exp, mant
(isneg, mant, exp) = flt32explode(val)
-> dragon4(buf, isneg, mant castto(int64), (exp - 52) castto(int64), Fltbias, mode, precision)
}
/*
buf: output buffer
e: exponent
p: precision
f: mantissa
flting value: x = f^(e - p)
*/
const dragon4 = {buf, isneg, f, e, p, mode, cutoff
var r, s, t, u, v, y
var udig
var mm, mp /* margins above and below */
var roundup
var low, high
var k, n
var a, i
/* if we have zero for the mantissa, we can return early */
n = 0
if isneg
n += encode(buf, '-')
;;
if f == 0
n += encode(buf[n:], '0')
n += encode(buf[n:], '.')
n += encode(buf[n:], '0')
-> 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)
/* 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)
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)
;;
while true
t = bigdup(r)
bigshli(t, 1)
bigadd(t, mp)
while true
u = bigdup(s)
bigshli(u, 1)
match bigcmp(t, u)
| `Before:
bigfree(u)
break
| _:
k++
bigmuli(s, 10)
bigfree(u)
;;
;;
if mode == 0
cutoff = k - buf.len - 1
else
if mode == 2
cutoff += k
;;
a = cutoff - k
y = bigdup(s)
if a < 0
for i = 0; i < a; i++
bigmuli(y, 10)
;;
else
for i = 0; i < -a; i++
bigaddi(y, 9)
bigdivi(y, 10)
;;
;;
match bigcmp(y, mm)
| `Before: /* nothing */
| _:
bigfree(mm)
mm = y
;;
match bigcmp(y, mp)
| `Before: /* nothing */
| _:
bigfree(mp)
mp = y
roundup = true
;;
;;
u = bigdup(s)
bigshli(u, 1)
match bigcmp(t, u)
| `Before:
bigfree(t)
bigfree(u)
break
| _:
;;
;;
if k <= 0
n += encode(buf[n:], '0')
n += encode(buf[n:], '.')
;;
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)
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
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)
;;
;;
-> 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
for i = 0; i < -k; i++
n += encode(buf[n:], '0')
;;
;;
buf[n++] = dig[d]
if k == 0
n += encode(buf[n:], '.')
;;
-> n
}