From e39561b7a9e74d39d061f8e153e48334a4facf3f Mon Sep 17 00:00:00 2001 From: Fredrik Tolf Date: Mon, 27 Jun 2022 14:45:14 +0200 Subject: [PATCH 1/1] bin: Added coding and decoding of floats. --- coe/bin.py | 50 ++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 48 insertions(+), 2 deletions(-) diff --git a/coe/bin.py b/coe/bin.py index b9ee601..08e521e 100644 --- a/coe/bin.py +++ b/coe/bin.py @@ -1,3 +1,4 @@ +import io, math from . import data T_END = 0 @@ -70,6 +71,30 @@ class encoder(object): dst.write(text.encode("utf-8")) dst.write(b'\0') + @staticmethod + def writefloat(dst, x): + if x == 0.0: + mnt, exp = (0, 0) + elif math.isinf(x): + if x > 0: + mnt, exp = (0, 2) + else: + mnt, exp = (0, 3) + elif math.isnan(x): + mnt, exp = (0, 4) + else: + mnt, exp = math.frexp(x) + mnt *= 2 + exp -= 1 + while mnt != int(mnt): + mnt *= 2 + mnt = int(mnt) + buf = bytearray() + buf.extend(encoder.encint(mnt)) + buf.extend(encoder.encint(exp)) + dst.write(encoder.encint(len(buf))) + dst.write(buf) + def dumpseq(self, dst, seq): for v in seq: self.dump(dst, v) @@ -103,6 +128,9 @@ class encoder(object): self.writetag(dst, T_BIT, 0, datum) dst.write(self.encint(len(datum))) dst.write(datum) + elif isinstance(datum, float): + self.writetag(dst, T_BIT, BIT_BFLOAT, datum) + self.writefloat(dst, datum) elif isinstance(datum, data.symbol): if datum.ns == "": self.writetag(dst, T_STR, STR_SYM, datum) @@ -265,10 +293,28 @@ class decoder(object): return self.addref(ret) elif pri == T_BIT: ln = self.loadint(fp) - ret = self.addref(fp.read(ln)) + ret = fp.read(ln) if len(ret) < ln: raise eoferror() - return ret + if sec == BIT_BFLOAT: + buf = io.BytesIO(ret) + mnt = self.loadint(buf) + exp = self.loadint(buf) + if mnt == 0: + if exp == 0: + return 0.0 + elif exp == 1: + return -0.0 + elif exp == 2: + return float("inf") + elif exp == 3: + return -float("inf") + else: + return float("nan") + else: + ret = math.ldexp(mnt, exp - (mnt.bit_length() - 1)) + return self.addref(ret) + return self.addref(ret) elif pri == T_NIL: if sec == NIL_TRUE: return self.addref(True) -- 2.11.0