CHERIoT RTOS
A compartmentalised RTOS for CHERIoT hardware
Toggle main menu visibility
Loading...
Searching...
No Matches
sdk
include
float_to_string_helpers.hh
1
#pragma once
2
// Copyright Benoit Blanchon and CHERIoT Contributors.
3
// SPDX-License-Identifier: MIT
4
//
5
// This code is derived from the ArduinoJson project:
6
// Copyright Benoit Blanchon 2014-2017
7
// MIT License
8
9
/**
10
* This file provides routines to help convert from floating-point values to
11
* strings.
12
*
13
* This uses the algorithm described here:
14
*
15
* https://blog.benoitblanchon.fr/lightweight-float-to-string/
16
*
17
* This approach is optimised for code size, not performance or accuracy. It
18
* will give more rounding errors than common implementations but is a fraction
19
* of the code size.
20
*/
21
22
#include <array>
23
#include <type_traits>
24
25
namespace
26
{
27
/**
28
* Number of powers of ten required to represent all values that fit in any
29
* supported floating-point type. 9 is sufficient for IEEE 754 64-bit
30
* floating-point values. Currently, CHERIoT does not provide a long
31
* double type.
32
*/
33
constexpr
size_t
NumberOfPowersOfTen
= 9;
34
35
/**
36
* Helper that computes the necessary value of `NumberOfPowersOfTen` for a
37
* given type.
38
*/
39
template
<
typename
T>
40
constexpr
size_t
NecessaryNumberOfPowersOfTen
= []() {
41
return
32 - __builtin_clz(std::numeric_limits<T>::max_exponent10);
42
}();
43
44
/**
45
* Set of supported floating-point types.
46
*
47
* If new types are added to the allowed list, the
48
* `NecessaryNumberOfPowersOfTen` part of the expression must also be
49
* updated.
50
*/
51
template
<
typename
T>
52
concept
SupportedFloatingPointType
=
requires
() {
53
requires
((std::is_same_v<T, float> || std::is_same_v<T, double>) &&
54
(
NecessaryNumberOfPowersOfTen<double>
<=
NumberOfPowersOfTen
));
55
};
56
57
/**
58
* Table of powers of ten. These are expensive to compute dynamically.
59
*/
60
template
<
typename
T>
61
constexpr
std::array<T, NumberOfPowersOfTen>
PositiveBinaryPowersOfTen
= {
62
static_cast<
T
>
(1e1),
63
static_cast<
T
>
(1e2),
64
static_cast<
T
>
(1e4),
65
static_cast<
T
>
(1e8),
66
static_cast<
T
>
(1e16),
67
static_cast<
T
>
(1e32),
68
static_cast<
T
>
(1e64),
69
static_cast<
T
>
(1e128),
70
static_cast<
T
>
(1e256)};
71
72
/**
73
* Table of negative powers of ten. These are expensive to compute
74
* dynamically.
75
*/
76
template
<
typename
T>
77
constexpr
std::array<T, NumberOfPowersOfTen>
NegativeBinaryPowersOfTen
= {
78
static_cast<
T
>
(1e-1),
79
static_cast<
T
>
(1e-2),
80
static_cast<
T
>
(1e-4),
81
static_cast<
T
>
(1e-8),
82
static_cast<
T
>
(1e-16),
83
static_cast<
T
>
(1e-32),
84
static_cast<
T
>
(1e-64),
85
static_cast<
T
>
(1e-128),
86
static_cast<
T
>
(1e-256)};
87
88
/// Largest value that is printed without an exponent
89
template
<
typename
T>
90
constexpr
T
PositiveExponentiationThreshold
= 1e7;
91
92
/// Smallest value that is printed without an exponent
93
template
<
typename
T>
94
constexpr
T
NegativeExponentiationThreshold
= 1e-5;
95
96
/**
97
* Scale the floating-point value up or down in powers of ten so that the
98
* decimal point will end up in a sensible place.
99
*
100
* The return value is the number of powers of ten (positive or negative)
101
* that the value was scaled by.
102
*
103
* This uses binary exponentiation, see the blog post linked at the top of
104
* the file for more details.
105
*/
106
template
<SupportedFloatingPo
int
Type T>
107
inline
int
normalize
(T &value)
108
{
109
int
powersOf10 = 0;
110
111
int8_t index =
NecessaryNumberOfPowersOfTen<T>
- 1;
112
int
bit = 1 << index;
113
114
if
(value >=
PositiveExponentiationThreshold<T>
)
115
{
116
for
(; index >= 0; index--)
117
{
118
if
(value >=
PositiveBinaryPowersOfTen<T>
[index])
119
{
120
value *=
NegativeBinaryPowersOfTen<T>
[index];
121
powersOf10 = (powersOf10 + bit);
122
}
123
bit >>= 1;
124
}
125
}
126
127
if
(value > 0 && value <=
NegativeExponentiationThreshold<T>
)
128
{
129
for
(; index >= 0; index--)
130
{
131
if
(value <
NegativeBinaryPowersOfTen<T>
[index] * 10)
132
{
133
value *=
PositiveBinaryPowersOfTen<T>
[index];
134
powersOf10 = (powersOf10 - bit);
135
}
136
bit >>= 1;
137
}
138
}
139
140
return
powersOf10;
141
}
142
143
/**
144
* A floating-point value decomposed into components for printing.
145
*/
146
struct
FloatParts
147
{
148
/// The integral component (before the decimal point).
149
uint32_t
integral
;
150
/// The decimal component (after the decimal point).
151
uint32_t
decimal
;
152
/// The exponent (the power of ten that this is raised to).
153
int16_t
exponent
;
154
/**
155
* The number of decimal places in the exponent. The exponent is
156
* represented as a value that can be converted to a string with
157
* integer-to-string conversion. This may have leading zeroes. For
158
* example, the number 123.045 will have an `integral` value of 123, a
159
* `decimal` value of 45, an `exponent` of 1, and a `decimalPlaces` of
160
* 3. The value 45 must therefore be printed with a leading zero.
161
*/
162
int8_t
decimalPlaces
;
163
};
164
165
constexpr
uint32_t pow10(
int
exponent)
166
{
167
return
(exponent == 0) ? 1 : 10 * pow10(exponent - 1);
168
}
169
170
template
<SupportedFloatingPo
int
Type T>
171
FloatParts decompose_float(T value, int8_t decimalPlaces)
172
{
173
uint32_t maxDecimalPart = pow10(decimalPlaces);
174
175
int
exponent =
normalize
(value);
176
177
uint32_t integral =
static_cast<
uint32_t
>
(value);
178
// reduce number of decimal places by the number of integral places
179
for
(uint32_t tmp = integral; tmp >= 10; tmp /= 10)
180
{
181
maxDecimalPart /= 10;
182
decimalPlaces--;
183
}
184
185
T remainder = (value - T(integral)) * T(maxDecimalPart);
186
187
uint32_t decimal = uint32_t(remainder);
188
remainder = remainder - T(decimal);
189
190
// rounding:
191
// increment by 1 if remainder >= 0.5
192
decimal += uint32_t(remainder * 2);
193
if
(decimal >= maxDecimalPart)
194
{
195
decimal = 0;
196
integral++;
197
if
(exponent && integral >= 10)
198
{
199
exponent++;
200
integral = 1;
201
}
202
}
203
204
// remove trailing zeros
205
while
(decimal % 10 == 0 && decimalPlaces > 0)
206
{
207
decimal /= 10;
208
decimalPlaces--;
209
}
210
211
return
{
212
integral, decimal,
static_cast<
int16_t
>
(exponent), decimalPlaces};
213
}
214
215
}
// namespace
anonymous_namespace{float_to_string_helpers.hh}::SupportedFloatingPointType
Set of supported floating-point types.
Definition
float_to_string_helpers.hh:52
anonymous_namespace{float_to_string_helpers.hh}::NumberOfPowersOfTen
constexpr size_t NumberOfPowersOfTen
Number of powers of ten required to represent all values that fit in any supported floating-point typ...
Definition
float_to_string_helpers.hh:33
anonymous_namespace{float_to_string_helpers.hh}::normalize
int normalize(T &value)
Scale the floating-point value up or down in powers of ten so that the decimal point will end up in a...
Definition
float_to_string_helpers.hh:107
anonymous_namespace{float_to_string_helpers.hh}::NegativeExponentiationThreshold
constexpr T NegativeExponentiationThreshold
Smallest value that is printed without an exponent.
Definition
float_to_string_helpers.hh:94
anonymous_namespace{float_to_string_helpers.hh}::NecessaryNumberOfPowersOfTen
constexpr size_t NecessaryNumberOfPowersOfTen
Helper that computes the necessary value of NumberOfPowersOfTen for a given type.
Definition
float_to_string_helpers.hh:40
anonymous_namespace{float_to_string_helpers.hh}::PositiveBinaryPowersOfTen
constexpr std::array< T, NumberOfPowersOfTen > PositiveBinaryPowersOfTen
Table of powers of ten.
Definition
float_to_string_helpers.hh:61
anonymous_namespace{float_to_string_helpers.hh}::NegativeBinaryPowersOfTen
constexpr std::array< T, NumberOfPowersOfTen > NegativeBinaryPowersOfTen
Table of negative powers of ten.
Definition
float_to_string_helpers.hh:77
anonymous_namespace{float_to_string_helpers.hh}::PositiveExponentiationThreshold
constexpr T PositiveExponentiationThreshold
Largest value that is printed without an exponent.
Definition
float_to_string_helpers.hh:90
anonymous_namespace{float_to_string_helpers.hh}::FloatParts
A floating-point value decomposed into components for printing.
Definition
float_to_string_helpers.hh:147
anonymous_namespace{float_to_string_helpers.hh}::FloatParts::exponent
int16_t exponent
The exponent (the power of ten that this is raised to).
Definition
float_to_string_helpers.hh:153
anonymous_namespace{float_to_string_helpers.hh}::FloatParts::integral
uint32_t integral
The integral component (before the decimal point).
Definition
float_to_string_helpers.hh:149
anonymous_namespace{float_to_string_helpers.hh}::FloatParts::decimal
uint32_t decimal
The decimal component (after the decimal point).
Definition
float_to_string_helpers.hh:151
anonymous_namespace{float_to_string_helpers.hh}::FloatParts::decimalPlaces
int8_t decimalPlaces
The number of decimal places in the exponent.
Definition
float_to_string_helpers.hh:162
Generated by
1.18.0