chiark / gitweb /
@@@ tty mess
[mLib] / struct / buf-float.c
1 /* -*-c-*-
2  *
3  * Encoding and decoding floating-point values
4  *
5  * (c) 2023 Straylight/Edgeware
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of the mLib utilities library.
11  *
12  * mLib is free software: you can redistribute it and/or modify it under
13  * the terms of the GNU Library General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or (at
15  * your option) any later version.
16  *
17  * mLib is distributed in the hope that it will be useful, but WITHOUT
18  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Library General Public
20  * License for more details.
21  *
22  * You should have received a copy of the GNU Library General Public
23  * License along with mLib.  If not, write to the Free Software
24  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
25  * USA.
26  */
27
28 /*----- Header files ------------------------------------------------------*/
29
30 #include <float.h>
31 #include <math.h>
32
33 #include "bits.h"
34 #include "buf.h"
35 #include "fltfmt.h"
36 #include "macros.h"
37
38 /*----- Constants ---------------------------------------------------------*/
39
40 /* Tolerable errors.  These aren't great, and all of them imply a failure to
41  * faithfully pass the value on, but they're also the inevitable consequence
42  * of having different floating-point systems.
43  */
44 #define IGNERR (FLTERR_INEXACT | FLTERR_OFLOW | FLTERR_UFLOW)
45
46 /*----- Main code ---------------------------------------------------------*/
47
48 #define FORMATS(_)                                                      \
49   _(flt, float, f32, 4)                                                 \
50   _(dbl, double, f64, 8)
51
52 /* --- @buf_getf{32,64}{,l,b} --- *
53  *
54  * Arguments:   @buf *b@ = a buffer to read from
55  *              @float *x_out@, @double *x_out@ = where to put the result
56  *
57  * Returns:     Zero on success, %$-1$% on failure (and the buffer is
58  *              broken).
59  *
60  * Use:         Get an IEEE Binary32 or Binary64 value from the buffer.
61  *              Conversion is performed using the `fltfmt' machinery, with
62  *              the usual round-to-nearest/ties-to-even rounding mode.
63  */
64
65 #define DEFGET1(ty, cty, fty, e, xe, w)                                 \
66   int GLUE3(buf_get, fty, xe)(buf *b, cty *x_out)                       \
67   {                                                                     \
68     const octet *p;                                                     \
69     unsigned err;                                                       \
70                                                                         \
71     p = buf_get(b, w); if (!p) return (-1);                             \
72     err = fltfmt_##fty##e##to##ty(x_out, p, FLTRND_NEAREVEN);           \
73       if (err&~IGNERR) { BBREAK(b); return (-1); }                      \
74     return (0);                                                         \
75   }                                                                     \
76   int (GLUE3(dbuf_get, fty, xe))(dbuf *db, cty *x_out)                  \
77     { return (GLUE3(dbuf_get, fty, xe)(db, x_out)); }
78
79 #define DEFGET(ty, cty, fty, w)                                         \
80   DEFGET1(ty, cty, fty, b, EMPTY, w)                                    \
81   DEFGET1(ty, cty, fty, l, l, w)                                        \
82   DEFGET1(ty, cty, fty, b, b, w)
83
84 FORMATS(DEFGET)
85
86 #undef DEFGET1
87 #undef DEFGET
88
89 /* --- @buf_putf{32,64}{,l,b} --- *
90  *
91  * Arguments:   @buf *b@ = a buffer to write to
92  *              @double x@ = a number to write
93  *
94  * Returns:     Zero on success, %$-1$% on failure (and the buffer is
95  *              broken).
96  *
97  * Use:         Get an IEEE Binary32 or Binary64 value from the buffer.
98  *              Conversion is performed using the `fltfmt' machinery, with
99  *              the usual round-to-nearest/ties-to-even rounding mode.
100  */
101
102 #define DEFPUT1(ty, cty, fty, e, xe, w)                                 \
103   int GLUE3(buf_put, fty, xe)(buf *b, cty x)                            \
104   {                                                                     \
105     octet *p;                                                           \
106     unsigned err;                                                       \
107                                                                         \
108     p = buf_get(b, w); if (!p) return (-1);                             \
109     err = fltfmt_##ty##to##fty##e(p, x, FLTRND_NEAREVEN);               \
110       if (err&~IGNERR) { BBREAK(b); return (-1); }                      \
111     return (0);                                                         \
112   }                                                                     \
113   int (GLUE3(dbuf_put, fty, xe))(dbuf *db, cty x)                       \
114     { return (GLUE3(dbuf_put, fty, xe)(db, x)); }
115
116 #define DEFPUT(ty, cty, fty, w)                                         \
117   DEFPUT1(ty, cty, fty, b, EMPTY, w)                                    \
118   DEFPUT1(ty, cty, fty, l, l, w)                                        \
119   DEFPUT1(ty, cty, fty, b, b, w)
120
121 FORMATS(DEFPUT)
122
123 #undef DEFPUT1
124 #undef DEFPUT
125
126 /*----- That's all, folks -------------------------------------------------*/