Extend floating point support
[babeltrace.git] / lib / types / float.c
CommitLineData
6dc2ca62
MD
1/*
2 * Common Trace Format
3 *
4 * Floating point read/write functions.
5 *
de0ba614 6 * Copyright (c) 2010 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
6dc2ca62 7 *
de0ba614
MD
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
6dc2ca62 21 *
de0ba614 22 * Reference: ISO C99 standard 5.2.4
6dc2ca62
MD
23 */
24
25#include <ctf/ctf-types.h>
26#include <glib.h>
de0ba614 27#include <float.h> /* C99 floating point definitions */
6dc2ca62
MD
28#include <endian.h>
29
de0ba614
MD
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
6dc2ca62
MD
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
de0ba614
MD
46#if (FLT_RADIX != 2)
47
48#error "Unsupported floating point radix"
49
6dc2ca62 50#endif
6dc2ca62
MD
51
52union 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
de0ba614
MD
61union 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
70struct pos_len {
71 size_t sign_start, exp_start, mantissa_start, len;
72};
73
74void ctf_float_copy(unsigned char *destp, const struct ctf_float *dest,
75 const unsigned char *src, const struct ctf_float *src)
6dc2ca62 76{
de0ba614
MD
77 unsigned long long tmp;
78 struct pos_len destpos, srcpos;
79
80 destpos.len = dest.exp_len + dest.mantissa_len;
81 if (dest.byte_order == LITTLE_ENDIAN) {
82 destpos.sign_start = destpos.len - 1;
83 destpos.exp_start = destpos.sign_start - dest->exp_len;
84 destpos.mantissa_start = 0;
85 } else {
86 destpos.sign_start = 0;
87 destpos.exp_start = 1;
88 destpos.mantissa_start = destpos.exp_start + dest->exp_len;
6dc2ca62 89 }
de0ba614
MD
90
91 srcpos.len = src.exp_len + src.mantissa_len;
92 if (src.byte_order == LITTLE_ENDIAN) {
93 srcpos.sign_start = srcpos.len - 1;
94 srcpos.exp_start = srcpos.sign_start - src->exp_len;
95 srcpos.mantissa_start = 0;
96 } else {
97 srcpos.sign_start = 0;
98 srcpos.exp_start = 1;
99 srcpos.mantissa_start = srcpos.exp_start + src->exp_len;
6dc2ca62 100 }
de0ba614
MD
101
102 /* sign */
103 tmp = bitfield_unsigned_read(ptr, srcpos.sign_start, 1,
104 src->byte_order);
105 bitfield_unsigned_write(&u.bits, destpos.sign_start, 1,
106 dest->byte_order, tmp);
107
108 /* mantissa (except sign). No sign extend. */
109 tmp = bitfield_unsigned_read(ptr, srcpos.mantissa_start,
110 src->mantissa_len - 1, src->byte_order);
111 bitfield_unsigned_write(&u.bits, destpos.mantissa_start,
112 dest->mantissa_len - 1, dest->byte_order, tmp);
113
114 /* exponent, with sign-extend. */
115 tmp = bitfield_signed_read(ptr, srcpos.exp_start, src->exp_len,
116 src->byte_order);
117 bitfield_signed_write(&u.bits, destpos.exp_start, dest->exp_len,
118 dest->byte_order, tmp);
6dc2ca62
MD
119}
120
de0ba614 121double ctf_double_read(const unsigned char *ptr, const struct ctf_float *src)
6dc2ca62 122{
de0ba614
MD
123 union doubleIEEE754 u;
124 struct ctf_float dest = {
125 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
126 .mantissa_len = DBL_MANT_DIG,
127 .byte_order = BYTE_ORDER,
128 };
129
130 float_copy(&u.bits, &dest, ptr, src);
131 return u.v;
132}
133
134size_t ctf_double_write(unsigned char *ptr, const struct ctf_float *dest,
135 double v)
136{
137 union doubleIEEE754 u;
138 struct ctf_float src = {
139 .exp_len = sizeof(double) * CHAR_BIT - DBL_MANT_DIG,
140 .mantissa_len = DBL_MANT_DIG,
141 .byte_order = BYTE_ORDER,
142 };
6dc2ca62
MD
143
144 if (!ptr)
145 goto end;
de0ba614
MD
146 u.v = v;
147 float_copy(ptr, dest, &u.bits, &src);
148end:
149 return len;
150}
6dc2ca62 151
de0ba614
MD
152long double ctf_ldouble_read(const unsigned char *ptr,
153 const struct ctf_float *src)
154{
155 union ldoubleIEEE754 u;
156 struct ctf_float dest = {
157 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
158 .mantissa_len = LDBL_MANT_DIG,
159 .byte_order = BYTE_ORDER,
160 };
161
162 float_copy(&u.bits, &dest, ptr, src);
163 return u.v;
164}
165
166size_t ctf_ldouble_write(unsigned char *ptr, const struct ctf_float *dest,
167 long double v)
168{
169 union ldoubleIEEE754 u;
170 struct ctf_float src = {
171 .exp_len = sizeof(double) * CHAR_BIT - LDBL_MANT_DIG,
172 .mantissa_len = LDBL_MANT_DIG,
173 .byte_order = BYTE_ORDER,
174 };
175
176 if (!ptr)
177 goto end;
178 u.v = v;
179 float_copy(ptr, dest, &u.bits, &src);
6dc2ca62
MD
180end:
181 return len;
182}
This page took 0.029883 seconds and 4 git commands to generate.