type classes: hash table
[babeltrace.git] / lib / types / float.c
1 /*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * This library is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU Lesser General Public
10 * License as published by the Free Software Foundation; either
11 * version 2.1 of the License, or (at your option) any later version.
12 *
13 * This library is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * Lesser General Public License for more details.
17 *
18 * You should have received a copy of the GNU Lesser General Public
19 * License along with this library; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
21 *
22 * Reference: ISO C99 standard 5.2.4
23 */
24
25 #include <ctf/ctf-types.h>
26 #include <glib.h>
27 #include <float.h> /* C99 floating point definitions */
28 #include <endian.h>
29
30 /*
31 * This library is limited to binary representation of floating point values.
32 * Sign-extension of the exponents is assumed to keep the NaN, +inf, -inf
33 * values, but this should be double-checked (TODO).
34 */
35
36 /*
37 * Aliasing float/double and unsigned long is not strictly permitted by strict
38 * aliasing, but in practice type prunning is well supported, and this permits
39 * us to use per-word read/writes rather than per-byte.
40 */
41
42 #if defined(__GNUC__) || defined(__MINGW32__) || defined(_MSC_VER)
43 #define HAS_TYPE_PRUNING
44 #endif
45
46 #if (FLT_RADIX != 2)
47
48 #error "Unsupported floating point radix"
49
50 #endif
51
52 union doubleIEEE754 {
53 double v;
54 #ifdef HAS_TYPE_PRUNING
55 unsigned long bits[(sizeof(double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
56 #else
57 unsigned char bits[sizeof(double)];
58 #endif
59 };
60
61 union ldoubleIEEE754 {
62 long double v;
63 #ifdef HAS_TYPE_PRUNING
64 unsigned long bits[(sizeof(long double) + sizeof(unsigned long) - 1) / sizeof(unsigned long)];
65 #else
66 unsigned char bits[sizeof(long double)];
67 #endif
68 };
69
70 struct pos_len {
71 size_t sign_start, exp_start, mantissa_start, len;
72 };
73
74 void ctf_float_copy(unsigned char *destp, const struct ctf_float *dest,
75 const unsigned char *src, const struct ctf_float *src)
76 {
77 struct pos_len destpos, srcpos;
78 union {
79 unsigned long long u;
80 long long s;
81 } tmp;
82
83 destpos.len = dest.exp_len + dest.mantissa_len;
84 if (dest.byte_order == LITTLE_ENDIAN) {
85 destpos.sign_start = destpos.len - 1;
86 destpos.exp_start = destpos.sign_start - dest->exp_len;
87 destpos.mantissa_start = 0;
88 } else {
89 destpos.sign_start = 0;
90 destpos.exp_start = 1;
91 destpos.mantissa_start = destpos.exp_start + dest->exp_len;
92 }
93
94 srcpos.len = src.exp_len + src.mantissa_len;
95 if (src.byte_order == LITTLE_ENDIAN) {
96 srcpos.sign_start = srcpos.len - 1;
97 srcpos.exp_start = srcpos.sign_start - src->exp_len;
98 srcpos.mantissa_start = 0;
99 } else {
100 srcpos.sign_start = 0;
101 srcpos.exp_start = 1;
102 srcpos.mantissa_start = srcpos.exp_start + src->exp_len;
103 }
104
105 /* sign */
106 tmp.u = bitfield_unsigned_read(ptr, srcpos.sign_start, 1,
107 src->byte_order);
108 bitfield_unsigned_write(&u.bits, destpos.sign_start, 1,
109 dest->byte_order, tmp.u);
110
111 /* mantissa (without leading 1). No sign extend. */
112 tmp.u = bitfield_unsigned_read(ptr, srcpos.mantissa_start,
113 src->mantissa_len - 1, src->byte_order);
114 bitfield_unsigned_write(&u.bits, destpos.mantissa_start,
115 dest->mantissa_len - 1, dest->byte_order, tmp.u);
116
117 /* exponent, with sign-extend. */
118 tmp.s = bitfield_signed_read(ptr, srcpos.exp_start, src->exp_len,
119 src->byte_order);
120 bitfield_signed_write(&u.bits, destpos.exp_start, dest->exp_len,
121 dest->byte_order, tmp.s);
122 }
123
124 double ctf_double_read(const unsigned char *ptr, const struct ctf_float *src)
125 {
126 union doubleIEEE754 u;
127 struct ctf_float dest = {
128 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
129 .mantissa_len = DBL_MANT_DIG,
130 .byte_order = BYTE_ORDER,
131 };
132
133 float_copy(&u.bits, &dest, ptr, src);
134 return u.v;
135 }
136
137 size_t ctf_double_write(unsigned char *ptr, const struct ctf_float *dest,
138 double v)
139 {
140 union doubleIEEE754 u;
141 struct ctf_float src = {
142 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
143 .mantissa_len = DBL_MANT_DIG,
144 .byte_order = BYTE_ORDER,
145 };
146
147 if (!ptr)
148 goto end;
149 u.v = v;
150 float_copy(ptr, dest, &u.bits, &src);
151 end:
152 return len;
153 }
154
155 long double ctf_ldouble_read(const unsigned char *ptr,
156 const struct ctf_float *src)
157 {
158 union ldoubleIEEE754 u;
159 struct ctf_float dest = {
160 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
161 .mantissa_len = LDBL_MANT_DIG,
162 .byte_order = BYTE_ORDER,
163 };
164
165 float_copy(&u.bits, &dest, ptr, src);
166 return u.v;
167 }
168
169 size_t ctf_ldouble_write(unsigned char *ptr, const struct ctf_float *dest,
170 long double v)
171 {
172 union ldoubleIEEE754 u;
173 struct ctf_float src = {
174 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
175 .mantissa_len = LDBL_MANT_DIG,
176 .byte_order = BYTE_ORDER,
177 };
178
179 if (!ptr)
180 goto end;
181 u.v = v;
182 float_copy(ptr, dest, &u.bits, &src);
183 end:
184 return len;
185 }
This page took 0.047976 seconds and 4 git commands to generate.