blob: 124d095d842769c7b65b45bbc1756f3eab5f8897 [file] [log] [blame]
Laurence Lundbladecc2ed342018-09-22 17:29:55 -07001/*==============================================================================
Laurence Lundbladecc2ed342018-09-22 17:29:55 -07002
Laurence Lundbladed92a6162018-11-01 11:38:35 +07003 Copyright (c) 2018, Laurence Lundblade.
4 All rights reserved.
Laurence Lundbladecc2ed342018-09-22 17:29:55 -07005
Laurence Lundbladed92a6162018-11-01 11:38:35 +07006 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions are
8 met:
9 * Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 * Redistributions in binary form must reproduce the above
12 copyright notice, this list of conditions and the following
13 disclaimer in the documentation and/or other materials provided
14 with the distribution.
15 * Neither the name of The Linux Foundation nor the names of its
16 contributors, nor the name "Laurence Lundblade" may be used to
17 endorse or promote products derived from this software without
18 specific prior written permission.
Laurence Lundbladecc2ed342018-09-22 17:29:55 -070019
Laurence Lundbladed92a6162018-11-01 11:38:35 +070020 THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
21 WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
22 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
23 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
24 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
27 BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
28 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
29 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
30 IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Laurence Lundbladecc2ed342018-09-22 17:29:55 -070031 ==============================================================================*/
Laurence Lundblade12d32c52018-09-19 11:25:27 -070032//
33// ieee754.h
34// Indefinite
35//
36// Created by Laurence Lundblade on 7/23/18.
37// Copyright © 2018 Laurence Lundblade. All rights reserved.
38//
39
40#ifndef ieee754_h
41#define ieee754_h
42
43#include <stdint.h>
44
45
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -070046
47/*
48 General comments
49
50 This is a complete in that it handles all conversion cases
51 including +/- infinity, +/- zero, subnormal numbers, qNaN, sNaN
52 and NaN payloads.
53
54 This confirms to IEEE 754-2008, but note that this doesn't
55 specify conversions, just the encodings.
56
57 NaN payloads are preserved with alignment on the LSB. The
58 qNaN bit is handled differently and explicity copied. It
59 is always the MSB of the significand. The NaN payload MSBs
60 (except the qNaN bit) are truncated when going from
61 double or single to half.
62
63 TODO: what does the C cast do with NaN payloads from
64 double to single?
65
66
67
68 */
69
Laurence Lundblade12d32c52018-09-19 11:25:27 -070070/*
71 Most simply just explicilty encode the type you want, single or double.
72 This works easily everywhere since standard C supports both
73 these types and so does qcbor. This encoder also supports
74 half precision and there's a few ways to use it to encode
75 floating point numbers in less space.
76
77 Without losing precision, you can encode a single or double
78 such that the special values of 0, NaN and Infinity encode
79 as half-precision. This CBOR decodoer and most others
80 should handle this properly.
81
82 If you don't mind losing precision, then you can use half-precision.
83 One way to do this is to set up your environment to use
84 ___fp_16. Some compilers and CPUs support it even though it is not
85 standard C. What is nice about this is that your program
86 will use less memory and floating point operations like
87 multiplying, adding and such will be faster.
88
89 Another way to make use of half-precision is to represent
90 the values in your program as single or double, but encode
91 them in CBOR as half-precision. This cuts the size
92 of the encoded messages by 2 or 4, but doesn't reduce
93 memory needs or speed because you are still using
94 single or double in your code.
95
96
97 encode:
98 - float as float
99 - double as double
100 - half as half
101 - float as half_precision, for environments that don't support a half-precision type
102 - double as half_precision, for environments that don't support a half-precision type
103 - float with NaN, Infinity and 0 as half
104 - double with NaN, Infinity and 0 as half
105
106
107
108
109 */
110
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700111
112
113/*
114 Convert single precision float to half-precision float.
115 Precision and NaN payload bits will be lost. Too large
116 values will round up to infinity and too small to zero.
117 */
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700118uint16_t IEEE754_FloatToHalf(float f);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700119
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700120
121/*
122 Convert half precision float to single precision float.
123 This is a loss-less conversion.
124 */
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700125float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
126
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700127
128/*
129 Convert double precision float to half-precision float.
130 Precision and NaN payload bits will be lost. Too large
131 values will round up to infinity and too small to zero.
132 */
Laurence Lundbladecc2ed342018-09-22 17:29:55 -0700133uint16_t IEEE754_DoubleToHalf(double d);
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700134
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700135
136/*
137 Convert half precision float to double precision float.
138 This is a loss-less conversion.
139 */
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700140double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
141
142
143
144
145#define IEEE754_UNION_IS_HALF 0
146#define IEEE754_UNION_IS_SINGLE 1
147#define IEEE754_UNION_IS_DOUBLE 2
148
149typedef struct {
150 uint8_t uTag; // One of IEEE754_IS_xxxx
151 union {
152 uint16_t u16;
153 uint32_t u32;
154 uint64_t u64;
155 };
156} IEEE754_union;
157
158
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700159/*
160 Converts double-precision to single-precision or half-precision if possible without
161 loss of precisions. If not, leaves it as a double. Only converts to single-precision
162 unless bAllowHalfPrecision is set.
163 */
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700164IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
165
166/*
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700167 Converts double-precision to single-precision if possible without
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700168 loss of precision. If not, leaves it as a double.
169 */
170static inline IEEE754_union IEEE754_DoubleToSmall(double d)
171{
172 return IEEE754_DoubleToSmallestInternal(d, 0);
173}
174
175
176/*
Laurence Lundblade8db3d3e2018-09-29 11:46:37 -0700177 Converts double-precision to single-precision or half-precision if possible without
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700178 loss of precisions. If not, leaves it as a double.
179 */
180static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
181{
182 return IEEE754_DoubleToSmallestInternal(d, 1);
183}
184
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700185/*
186 Converts single-precision to half-precision if possible without
187 loss of precision. If not leaves as single-precision.
188 */
189IEEE754_union IEEE754_FloatToSmallest(float f);
190
191
Laurence Lundblade12d32c52018-09-19 11:25:27 -0700192#endif /* ieee754_h */
193
194
195
196
197
198
199