blob: ced4bcb4f1d93668076ed120ceb1c92e086e84f8 [file] [log] [blame]
Laurence Lundblade12d32c52018-09-19 11:25:27 -07001//
2// ieee754.h
3// Indefinite
4//
5// Created by Laurence Lundblade on 7/23/18.
6// Copyright © 2018 Laurence Lundblade. All rights reserved.
7//
8
9#ifndef ieee754_h
10#define ieee754_h
11
12#include <stdint.h>
13
14
15/*
16 Most simply just explicilty encode the type you want, single or double.
17 This works easily everywhere since standard C supports both
18 these types and so does qcbor. This encoder also supports
19 half precision and there's a few ways to use it to encode
20 floating point numbers in less space.
21
22 Without losing precision, you can encode a single or double
23 such that the special values of 0, NaN and Infinity encode
24 as half-precision. This CBOR decodoer and most others
25 should handle this properly.
26
27 If you don't mind losing precision, then you can use half-precision.
28 One way to do this is to set up your environment to use
29 ___fp_16. Some compilers and CPUs support it even though it is not
30 standard C. What is nice about this is that your program
31 will use less memory and floating point operations like
32 multiplying, adding and such will be faster.
33
34 Another way to make use of half-precision is to represent
35 the values in your program as single or double, but encode
36 them in CBOR as half-precision. This cuts the size
37 of the encoded messages by 2 or 4, but doesn't reduce
38 memory needs or speed because you are still using
39 single or double in your code.
40
41
42 encode:
43 - float as float
44 - double as double
45 - half as half
46 - float as half_precision, for environments that don't support a half-precision type
47 - double as half_precision, for environments that don't support a half-precision type
48 - float with NaN, Infinity and 0 as half
49 - double with NaN, Infinity and 0 as half
50
51
52
53
54 */
55
56int16_t IEEE754_FloatToHalf(float f);
57
58float IEEE754_HalfToFloat(uint16_t uHalfPrecision);
59
60int16_t IEEE754_DoubleToHalf(double d);
61
62double IEEE754_HalfToDouble(uint16_t uHalfPrecision);
63
64
65
66
67#define IEEE754_UNION_IS_HALF 0
68#define IEEE754_UNION_IS_SINGLE 1
69#define IEEE754_UNION_IS_DOUBLE 2
70
71typedef struct {
72 uint8_t uTag; // One of IEEE754_IS_xxxx
73 union {
74 uint16_t u16;
75 uint32_t u32;
76 uint64_t u64;
77 };
78} IEEE754_union;
79
80
81IEEE754_union IEEE754_DoubleToSmallestInternal(double d, int bAllowHalfPrecision);
82
83/*
84 Converts double-precision to half- or single-precision if possible without
85 loss of precision. If not, leaves it as a double.
86 */
87static inline IEEE754_union IEEE754_DoubleToSmall(double d)
88{
89 return IEEE754_DoubleToSmallestInternal(d, 0);
90}
91
92
93/*
94 Converts double-precision to single-precision if possible without
95 loss of precisions. If not, leaves it as a double.
96 */
97static inline IEEE754_union IEEE754_DoubleToSmallest(double d)
98{
99 return IEEE754_DoubleToSmallestInternal(d, 1);
100}
101
102
103/*
104 Converts single-precision to half-precision if possible without
105 loss of precision. If not leaves as single-precision.
106 */
107IEEE754_union IEEE754_FloatToSmallest(float f);
108
109
110
111
112
113
114
115
116#endif /* ieee754_h */
117
118
119
120
121
122
123