8000 Fixed too many decimals places in float serialization (issue #543) · trinhduc/ArduinoJson@d41f7a8 · GitHub
[go: up one dir, main page]

Skip to content

Commit d41f7a8

Browse files
committed
Fixed too many decimals places in float serialization (issue bblanchon#543)
1 parent abfd399 commit d41f7a8

File tree

9 files changed

+201
-174
lines changed

9 files changed

+201
-174
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ HEAD
88
* Fixed warning "dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]"
99
* Fixed warning "floating constant exceeds range of 'float' [-Woverflow]" (issue #544)
1010
* Removed `ARDUINOJSON_DOUBLE_IS_64BITS` as it became useless.
11+
* Fixed too many decimals places in float serialization (issue #543)
1112

1213
v5.11.0
1314
-------

src/ArduinoJson/Polyfills/normalize.hpp

Lines changed: 0 additions & 46 deletions
This file was deleted.
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Copyright Benoit Blanchon 2014-2017
2+
// MIT License
3+
//
4+
// Arduino JSON library
5+
// https://bblanchon.github.io/ArduinoJson/
6+
// If you like this project, please add a star!
7+
8+
#pragma once
9+
10+
#include "../Configuration.hpp"
11+
#include "../Polyfills/math.hpp"
12+
#include "../TypeTraits/FloatTraits.hpp"
13+
14+
namespace ArduinoJson {
15+
namespace Internals {
16+
17+
template <typename TFloat>
18+
struct FloatParts {
19+
uint32_t integral;
20+
uint32_t decimal;
21+
int16_t exponent;
22+
int8_t decimalPlaces;
23+
24+
FloatParts(TFloat value) {
25+
const uint32_t maxDecimalPart = sizeof(TFloat) >= 8 ? 1000000000 : 1000000;
26+
27+
exponent = normalize(value);
28+
29+
integral = uint32_t(value);
30+
TFloat remainder = value - TFloat(integral);
31+
32+
remainder *= maxDecimalPart;
33+
decimal = uint32_t(remainder);
34+
remainder = remainder - TFloat(decimal);
35+
36+
// rounding:
37+
// increment by 1 if remainder >= 0.5
38+
decimal += uint32_t(remainder * 2);
39+
if (decimal >= maxDecimalPart) {
40+
decimal = 0;
41+
integral++;
42+
if (exponent && integral >= 10) {
43+
exponent++;
44+
integral = 1;
45+
}
46+
}
47+
48+
decimalPlaces = sizeof(TFloat) >= 8 ? 9 : 6;
49+
50+
// recude number of decimal places by the number of integral places
51+
for (uint32_t tmp = integral; tmp >= 10; tmp /= 10) {
52+
decimal /= 10;
53+
decimalPlaces--;
54+
}
55+
56+
// remove trailing zeros
57+
while (decimal % 10 == 0 && decimalPlaces > 0) {
58+
decimal /= 10;
59+
decimalPlaces--;
60+
}
61+
}
62+
63+
static int16_t normalize(TFloat& value) {
64+
typedef TypeTraits::FloatTraits<TFloat> traits;
65+
int16_t powersOf10 = 0;
66+
67+
int8_t index = sizeof(TFloat) == 8 ? 8 : 5;
68+
int bit = 1 << index;
69+
70+
if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) {
71+
for (; index >= 0; index--) {
72+
if (value >= traits::positiveBinaryPowerOfTen(index)) {
73+
value *= traits::negativeBinaryPowerOfTen(index);
74+
powersOf10 = int16_t(powersOf10 + bit);
75+
}
76+
bit >>= 1;
77+
}
78+
}
79+
80+
if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) {
81+
for (; index >= 0; index--) {
82+
if (value < traits::negativeBinaryPowerOfTenPlusOne(index)) {
83+
value *= traits::positiveBinaryPowerOfTen(index);
84+
powersOf10 = int16_t(powersOf10 - bit);
85+
}
86+
bit >>= 1;
87+
}
88+
}
89+
90+
return powersOf10;
91+
}
92+
};
93+
}
94+
}

src/ArduinoJson/Serialization/JsonWriter.hpp

Lines changed: 13 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,9 @@
99

1010
#include <stdint.h>
1111
#include "../Data/Encoding.hpp"
12-
#include "../Data/JsonFloat.hpp"
1312
#include "../Data/JsonInteger.hpp"
1413
#include "../Polyfills/attributes.hpp"
15-
#include "../Polyfills/math.hpp"
16-
#include "../Polyfills/normalize.hpp"
17-
#include "../TypeTraits/FloatTraits.hpp"
14+
#include "../Serialization/FloatParts.hpp"
1815

1916
namespace ArduinoJson {
2017
namespace Internals {
@@ -28,10 +25,6 @@ namespace Internals {
2825
// indentation.
2926
template <typename Print>
3027
class JsonWriter {
31-
static const uint8_t maxDecimalPlaces = sizeof(JsonFloat) >= 8 ? 9 : 6;
32-
static const uint32_t maxDecimalPart =
33-
sizeof(JsonFloat) >= 8 ? 1000000000 : 1000000;
34-
3528
public:
3629
explicit JsonWriter(Print &sink) : _sink(sink), _length(0) {}
3730

@@ -87,7 +80,8 @@ class JsonWriter {
8780
}
8881
}
8982

90-
void writeFloat(JsonFloat value) {
83+
template <typename TFloat>
84+
void writeFloat(TFloat value) {
9185
if (Polyfills::isNaN(value)) return writeRaw("NaN");
9286

9387
if (value < 0.0) {
@@ -97,28 +91,27 @@ class JsonWriter {
9791

9892
if (Polyfills::isInfinity(value)) return writeRaw("Infinity");
9993

100-
uint32_t integralPart, decimalPart;
101-
int16_t powersOf10;
102-
splitFloat(value, integralPart, decimalPart, powersOf10);
94+
FloatParts<TFloat> parts(value);
10395

104-
writeInteger(integralPart);
105-
if (decimalPart) writeDecimals(decimalPart, maxDecimalPlaces);
96+
writeInteger(parts.integral);
97+
if (parts.decimalPlaces) writeDecimals(parts.decimal, parts.decimalPlaces);
10698

107-
if (powersOf10 < 0) {
99+
if (parts.exponent < 0) {
108100
writeRaw("e-");
109-
writeInteger(-powersOf10);
101+
writeInteger(-parts.exponent);
110102
}
111103

112-
if (powersOf10 > 0) {
104+
if (parts.exponent > 0) {
113105
writeRaw('e');
114-
writeInteger(powersOf10);
106+
writeInteger(parts.exponent);
115107
}
116108
}
117109

118110
template <typename UInt>
119111
void writeInteger(UInt value) {
120112
char buffer[22];
121-
char *ptr = buffer + sizeof(buffer) - 1;
113+
char *end = buffer + sizeof(buffer) - 1;
114+
char *ptr = end;
122115

123116
*ptr = 0;
124117
do {
@@ -130,15 +123,9 @@ class JsonWriter {
130123
}
131124

132125
void writeDecimals(uint32_t value, int8_t width) {
133-
// remove trailing zeros
134-
while (value % 10 == 0 && width > 0) {
135-
value /= 10;
136-
width--;
137-
}
138-
139126
// buffer should be big enough for all digits, the dot and the null
140127
// terminator
141-
char buffer[maxDecimalPlaces + 2];
128+
char buffer[16];
142129
char *ptr = buffer + sizeof(buffer) - 1;
143130

144131
// write the string in reverse order
@@ -166,30 +153,6 @@ class JsonWriter {
166153

167154
private:
168155
JsonWriter &operator=(const JsonWriter &); // cannot be assigned
169-
170-
void splitFloat(JsonFloat value, uint32_t &integralPart,
171-
uint32_t &decimalPart, int16_t &powersOf10) {
172-
powersOf10 = Polyfills::normalize(value);
173-
174-
integralPart = uint32_t(value);
175-
JsonFloat remainder = value - JsonFloat(integralPart);
176-
177-
remainder *= maxDecimalPart;
178-
decimalPart = uint32_t(remainder);
179-
remainder = remainder - JsonFloat(decimalPart);
180-
181-
// rounding:
182-
// increment by 1 if remainder >= 0.5
183-
decimalPart += uint32_t(remainder * 2);
184-
if (decimalPart >= maxDecimalPart) {
185-
decimalPart = 0;
186-
integralPart++;
187-
if (powersOf10 && integralPart >= 10) {
188-
powersOf10++;
189-
integralPart = 1;
190-
}
191-
}
192-
}
193156
};
194157
}
195158
}

0 commit comments

Comments
 (0)
0