blob: ba2b030f51294b514974a55f7bd69fbad43dfd3e [file] [log] [blame]
Laurence Lundbladecc2ed342018-09-22 17:29:55 -07001/*==============================================================================
2 Copyright 2018 Laurence Lundblade
3
4 Permission is hereby granted, free of charge, to any person obtaining
5 a copy of this software and associated documentation files (the
6 "Software"), to deal in the Software without restriction, including
7 without limitation the rights to use, copy, modify, merge, publish,
8 distribute, sublicense, and/or sell copies of the Software, and to
9 permit persons to whom the Software is furnished to do so, subject to
10 the following conditions:
11
12 The above copyright notice and this permission notice shall be included
13 in all copies or substantial portions of the Software.
14
15 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19 BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22 SOFTWARE.
23
24 (This is the MIT license)
25 ==============================================================================*/
Laurence Lundblade12d32c52018-09-19 11:25:27 -070026//
27// ieee754.h
28// Indefinite
29//
30// Created by Laurence Lundblade on 7/23/18.
31// Copyright © 2018 Laurence Lundblade. All rights reserved.
32//
33
34#ifndef ieee754_h
35#define ieee754_h
36
37#include <stdint.h>
38
39
40/*
41 Most simply just explicilty encode the type you want, single or double.
42 This works easily everywhere since standard C supports both
43 these types and so does qcbor. This encoder also supports
44 half precision and there's a few ways to use it to encode
45 floating point numbers in less space.
46
47 Without losing precision, you can encode a single or double
48 such that the special values of 0, NaN and Infinity encode
49 as half-precision. This CBOR decodoer and most others
50 should handle this properly.
51
52 If you don't mind losing precision, then you can use half-precision.
53 One way to do this is to set up your environment to use
54 ___fp_16. Some compilers and CPUs support it even though it is not
55 standard C. What is nice about this is that your program
56 will use less memory and floating point operations like
57 multiplying, adding and such will be faster.
58
59 Another way to make use of half-precision is to represent
60 the values in your program as single or double, but encode
61 them in CBOR as half-precision. This cuts the size
62 of the encoded messages by 2 or 4, but doesn't reduce
63 memory needs or speed because you are still using
64 single or double in your code.
65
66
67 encode:
68 - float as float
69 - double as double
70 - half as half
71 - float as half_precision, for environments that don't support a half-precision type
72 - double as half_precision, for environments that don't support a half-precision type
73 - float with NaN, Infinity and 0 as half
74 - double with NaN, Infinity and 0 as half
75
76
77
78
79 */
80
Laurence Lundbladecc2ed342018-09-22 17:29:55 -070081uint16_t IEEE754_FloatToHalf(float f);
Laurence Lundblade12d32c52018-09-19 11:25:27 -070082
83float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
84
Laurence Lundbladecc2ed342018-09-22 17:29:55 -070085uint16_t IEEE754_DoubleToHalf(double d);
Laurence Lundblade12d32c52018-09-19 11:25:27 -070086
87double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
88
89
90
91
92#define IEEE754_UNION_IS_HALF 0
93#define IEEE754_UNION_IS_SINGLE 1
94#define IEEE754_UNION_IS_DOUBLE 2
95
96typedef struct {
97 uint8_t uTag; // One of IEEE754_IS_xxxx
98 union {
99 uint16_t u16;
100 uint32_t u32;
101 uint64_t u64;
102 };
103} IEEE754_union;
104
105
106IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
107
108/*
109 Converts double-precision to half- or single-precision if possible without
110 loss of precision. If not, leaves it as a double.
111 */
112static inline IEEE754_union IEEE754_DoubleToSmall(double d)
113{
114 return IEEE754_DoubleToSmallestInternal(d, 0);
115}
116
117
118/*
119 Converts double-precision to single-precision if possible without
120 loss of precisions. If not, leaves it as a double.
121 */
122static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
123{
124 return IEEE754_DoubleToSmallestInternal(d, 1);
125}
126
127
128/*
129 Converts single-precision to half-precision if possible without
130 loss of precision. If not leaves as single-precision.
131 */
132IEEE754_union IEEE754_FloatToSmallest(float f);
133
134
135
136
137
138
139
140
141#endif /* ieee754_h */
142
143
144
145
146
147
148