Skip to content

Commit 1029eae

Browse files
committed
FEAT: Bincode - added support for writing FLOAT16, FLOAT and DOUBLE values
1 parent 820a3ab commit 1029eae

File tree

2 files changed

+87
-3
lines changed

2 files changed

+87
-3
lines changed

src/core/u-bincode.c

+70-3
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,6 @@
7676
// FLOAT16 credits: Steven Pigeon
7777
// https://hbfs.wordpress.com/2013/02/12/float16/
7878
typedef union {
79-
// float16 v;
8079
struct {
8180
// type determines alignment!
8281
u16 m : 10;
@@ -101,12 +100,21 @@ typedef union {
101100
float float16to32(float16_s f16) {
102101
// back to 32
103102
float32_s f32;
103+
#ifndef USE_NO_INFINITY
104+
if (f16.bits.e == 31) { // inifinity or nan
105+
return (f16.bits.m == 0) ? (f16.bits.s ? -1.0 : 1.0) * INFINITY : NAN;
106+
}
107+
#endif
104108
f32.bits.s = f16.bits.s;
105109
f32.bits.e = (f16.bits.e - 15) + 127; // safe in this direction
106110
f32.bits.m = ((u32)f16.bits.m) << 13;
107111
return f32.v;
108112
}
109113

114+
//float float64to16(float16_s f16) {
115+
// half s;
116+
//}
117+
110118
#pragma pack(4)
111119
typedef union {
112120
u16 num;
@@ -233,10 +241,16 @@ static REBCNT EncodedU32_Size(u32 value) {
233241
REBCNT inBit, nbits;
234242
REBYTE *cp, *bp, *ep;
235243
REBCNT n, count, index, tail, tail_new;
244+
REBDEC dbl;
245+
REBD32 d32;
236246
i32 i, len;
237247
u64 u;
238248
i64 si;
239249
u32 ulong;
250+
u16 ushort;
251+
float16_s f16;
252+
float32_s f32;
253+
240254

241255
ms_datetime* msdt = NULL;
242256
ms_date* msd = NULL;
@@ -502,7 +516,26 @@ static REBCNT EncodedU32_Size(u32 value) {
502516
continue;
503517
}
504518
goto error;
505-
519+
520+
case SYM_FLOAT:
521+
if (IS_INTEGER(next) || IS_DECIMAL(next)) {
522+
count += 4;
523+
continue;
524+
}
525+
goto error;
526+
case SYM_DOUBLE:
527+
if (IS_INTEGER(next) || IS_DECIMAL(next)) {
528+
count += 8;
529+
continue;
530+
}
531+
goto error;
532+
case SYM_FLOAT16:
533+
if (IS_INTEGER(next) || IS_DECIMAL(next)) {
534+
count += 2;
535+
continue;
536+
}
537+
goto error;
538+
506539
case SYM_UNIXTIME_NOW:
507540
case SYM_UNIXTIME_NOW_LE:
508541
value--; //there is no argument so no next
@@ -762,6 +795,41 @@ static REBCNT EncodedU32_Size(u32 value) {
762795
memcpy(cp, VAL_BIN_AT(next), n);
763796
VAL_INDEX(buffer_write) += 4; //for the length byte;
764797
break;
798+
799+
case SYM_FLOAT:
800+
f32.v = (float)(IS_INTEGER(next) ? VAL_INT64(next) : VAL_DECIMAL(next));
801+
memcpy(cp, (REBYTE*)&f32, 4);
802+
cp += 4;
803+
break;
804+
case SYM_DOUBLE:
805+
dbl = (REBDEC)(IS_INTEGER(next) ? VAL_INT64(next) : VAL_DECIMAL(next));
806+
memcpy(cp, (REBYTE*)&dbl, 8);
807+
cp += 8;
808+
break;
809+
case SYM_FLOAT16:
810+
d32 = (REBDEC)(IS_INTEGER(next) ? VAL_INT64(next) : VAL_DECIMAL(next));
811+
if (isnan(d32)) { // 1.#NaN
812+
ushort = 0x7e00;
813+
} else {
814+
// based on: https://stackoverflow.com/a/15118210/494472
815+
ulong = *((u32*)&d32);
816+
u32 t1 = (ulong & 0x7fffffff) >> 13; // Non-sign bits; Align mantissa on MSB
817+
u32 t2 = (ulong & 0x80000000) >> 16; // Sign bit; Shift sign bit into position
818+
u32 t3 = ulong & 0x7f800000; // Exponent
819+
820+
t1 -= 0x1c000; // Adjust bias
821+
t1 = (t3 < 0x38800000) ? 0 : t1; // Flush-to-zero
822+
t1 = (t3 > 0x47000000) ? 0x7bff : t1; // Clamp-to-max
823+
// NOTE: now infinity value is also clamped to max, is it ok?
824+
825+
t1 |= t2; // Re-insert sign bit
826+
827+
ushort = (u16)t1;
828+
}
829+
memcpy(cp, (REBYTE*)&ushort, 2);
830+
cp += 2;
831+
break;
832+
765833
case SYM_AT:
766834
VAL_INDEX(buffer_write) = VAL_INT32(next) - 1;
767835
cp = BIN_DATA(bin) + VAL_INDEX(buffer_write);
@@ -1352,7 +1420,6 @@ static REBCNT EncodedU32_Size(u32 value) {
13521420
case SYM_FLOAT16:
13531421
n = 2;
13541422
ASSERT_READ_SIZE(value, cp, ep, n);
1355-
float16_s f16;
13561423
f16.bytes.low = cp[0];
13571424
f16.bytes.high = cp[1];
13581425
SET_DECIMAL(temp, float16to32(f16) );

src/tests/units/bincode-test.r3

+17
Original file line numberDiff line numberDiff line change
@@ -323,6 +323,23 @@ is-protected-error?: func[code][
323323
--assert 1.0 = binary/read #{0000803F} 'FLOAT
324324
--assert 1.0 = binary/read #{000000000000F03F} 'DOUBLE
325325

326+
--test-- "BinCode - FLOAT16, FLOAT, DOUBLE (write)"
327+
b: binary/write #{} [float16 0.5 float16 1000 float16 32.5 float16 -32.5]
328+
--assert b/buffer = #{0038D063105010D0}
329+
--assert [0.5 1000.0 32.5 -32.5] = binary/read b [float16 float16 float16 float16]
330+
b: binary/write #{} [float 0.5 float 1000 float 32.5 float -32.5]
331+
--assert b/buffer = #{0000003F00007A4400000242000002C2}
332+
--assert [0.5 1000.0 32.5 -32.5] = binary/read b [float float float float]
333+
b: binary/write #{} [double 0.5 double 1000 double 32.5 double -32.5]
334+
--assert b/buffer = #{000000000000E03F0000000000408F40000000000040404000000000004040C0}
335+
--assert [0.5 1000.0 32.5 -32.5] = binary/read b [double double double double]
336+
337+
--test-- "BinCode - FLOAT16, FLOAT, DOUBLE (write/read NAN)"
338+
b: binary/write #{} [float16 1.#NaN float 1.#NaN double 1.#NaN]
339+
--assert b/buffer = #{007E0000C07F000000000000F87F}
340+
;@@ using MOLD as: 1.#nan <> 1.#nan
341+
--assert "[1.#NaN 1.#NaN 1.#NaN]" = mold binary/read b [float16 float double]
342+
326343
--test-- "BinCode - MSDOS-DATETIME"
327344
;- old and not much precise format for storing date and time from MS-DOS times
328345
;- still used in some file formats, like ZIP

0 commit comments

Comments
 (0)