mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed error in float serialization (issue #324)
This commit is contained in:
		
							
								
								
									
										13
									
								
								CHANGELOG.md
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								CHANGELOG.md
									
									
									
									
									
								
							| @@ -1,6 +1,11 @@ | ||||
| ArduinoJson: change log | ||||
| ======================= | ||||
|  | ||||
| HEAD | ||||
| ---- | ||||
|  | ||||
| * Fixed error in float serialization (issue #324) | ||||
|  | ||||
| v5.6.3 | ||||
| ------ | ||||
|  | ||||
| @@ -112,7 +117,7 @@ v5.0.3 | ||||
| v5.0.2 | ||||
| ------ | ||||
|  | ||||
| * Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the  | ||||
| * Fixed segmentation fault in `parseObject(String)` and `parseArray(String)`, when the | ||||
|   `StaticJsonBuffer` is too small to hold a copy of the string | ||||
| * Fixed Clang warning "register specifier is deprecated" (issue #102) | ||||
| * Fixed GCC warning "declaration shadows a member" (issue #103) | ||||
| @@ -228,14 +233,14 @@ v3.1 | ||||
|  | ||||
| Old generator API: | ||||
|  | ||||
| 	JsonObject<3> root;  | ||||
| 	JsonObject<3> root; | ||||
|     root.add("sensor", "gps"); | ||||
|     root.add("time", 1351824120); | ||||
|     root.add("data", array); | ||||
|  | ||||
| New generator API: | ||||
|  | ||||
| 	JsonObject<3> root;  | ||||
| 	JsonObject<3> root; | ||||
|     root["sensor"] = "gps"; | ||||
|     root["time"] = 1351824120; | ||||
|     root["data"] = array; | ||||
| @@ -292,7 +297,7 @@ v1.1 | ||||
| * Example: changed `char* json` into `char[] json` so that the bytes are not write protected | ||||
| * Fixed parsing bug when the JSON contains multi-dimensional arrays | ||||
|  | ||||
| v1.0  | ||||
| v1.0 | ||||
| ---- | ||||
|  | ||||
| Initial release | ||||
|   | ||||
| @@ -81,7 +81,7 @@ class JsonWriter { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   void writeFloat(JsonFloat value, int digits = 2) { | ||||
|   void writeFloat(JsonFloat value, uint8_t digits = 2) { | ||||
|     if (Polyfills::isNaN(value)) return writeRaw("NaN"); | ||||
|  | ||||
|     if (value < 0.0) { | ||||
| @@ -98,6 +98,9 @@ class JsonWriter { | ||||
|       powersOf10 = 0; | ||||
|     } | ||||
|  | ||||
|     // Round up last digit (so that print(1.999, 2) prints as "2.00") | ||||
|     value += getRoundingBias(digits); | ||||
|  | ||||
|     // Extract the integer part of the value and print it | ||||
|     JsonUInt int_part = static_cast<JsonUInt>(value); | ||||
|     JsonFloat remainder = value - static_cast<JsonFloat>(int_part); | ||||
| @@ -115,9 +118,6 @@ class JsonWriter { | ||||
|       char currentDigit = char(remainder); | ||||
|       remainder -= static_cast<JsonFloat>(currentDigit); | ||||
|  | ||||
|       // Round up last digit (so that print(1.999, 2) prints as "2.00") | ||||
|       if (digits == 0 && remainder >= 0.5) currentDigit++; | ||||
|  | ||||
|       // Print | ||||
|       writeRaw(char('0' + currentDigit)); | ||||
|     } | ||||
| @@ -135,16 +135,15 @@ class JsonWriter { | ||||
|  | ||||
|   void writeInteger(JsonUInt value) { | ||||
|     char buffer[22]; | ||||
|     char *ptr = buffer + sizeof(buffer) - 1; | ||||
|  | ||||
|     uint8_t i = 0; | ||||
|     *ptr = 0; | ||||
|     do { | ||||
|       buffer[i++] = static_cast<char>(value % 10 + '0'); | ||||
|       *--ptr = static_cast<char>(value % 10 + '0'); | ||||
|       value /= 10; | ||||
|     } while (value); | ||||
|  | ||||
|     while (i > 0) { | ||||
|       writeRaw(buffer[--i]); | ||||
|     } | ||||
|     writeRaw(ptr); | ||||
|   } | ||||
|  | ||||
|   void writeRaw(const char *s) { | ||||
| @@ -160,6 +159,26 @@ class JsonWriter { | ||||
|  | ||||
|  private: | ||||
|   JsonWriter &operator=(const JsonWriter &);  // cannot be assigned | ||||
|  | ||||
|   static JsonFloat getLastDigit(uint8_t digits) { | ||||
|     // Designed as a compromise between code size and speed | ||||
|     switch (digits) { | ||||
|       case 0: | ||||
|         return 1e-0; | ||||
|       case 1: | ||||
|         return 1e-1; | ||||
|       case 2: | ||||
|         return 1e-2; | ||||
|       case 3: | ||||
|         return 1e-3; | ||||
|       default: | ||||
|         return getLastDigit(uint8_t(digits - 4)) * 1e-4; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   FORCE_INLINE static JsonFloat getRoundingBias(uint8_t digits) { | ||||
|     return 0.5 * getLastDigit(digits); | ||||
|   } | ||||
| }; | ||||
| } | ||||
| } | ||||
|   | ||||
							
								
								
									
										113
									
								
								test/JsonWriter_WriteFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										113
									
								
								test/JsonWriter_WriteFloat_Tests.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,113 @@ | ||||
| // Copyright Benoit Blanchon 2014-2016 | ||||
| // MIT License | ||||
| // | ||||
| // Arduino JSON library | ||||
| // https://github.com/bblanchon/ArduinoJson | ||||
| // If you like this project, please add a star! | ||||
|  | ||||
| #include <gtest/gtest.h> | ||||
| #include <limits> | ||||
|  | ||||
| #include <ArduinoJson/Internals/JsonWriter.hpp> | ||||
| #include <ArduinoJson/Internals/StaticStringBuilder.hpp> | ||||
|  | ||||
| using namespace ArduinoJson::Internals; | ||||
|  | ||||
| class JsonWriter_WriteFloat_Tests : public testing::Test { | ||||
|  protected: | ||||
|   void whenInputIs(double input, uint8_t digits = 2) { | ||||
|     StaticStringBuilder sb(buffer, sizeof(buffer)); | ||||
|     JsonWriter writer(sb); | ||||
|     writer.writeFloat(input, digits); | ||||
|     returnValue = writer.bytesWritten(); | ||||
|   } | ||||
|  | ||||
|   void outputMustBe(const char *expected) { | ||||
|     EXPECT_STREQ(expected, buffer); | ||||
|     EXPECT_EQ(strlen(expected), returnValue); | ||||
|   } | ||||
|  | ||||
|  private: | ||||
|   char buffer[1024]; | ||||
|   size_t returnValue; | ||||
| }; | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, NaN) { | ||||
|   whenInputIs(std::numeric_limits<double>::signaling_NaN()); | ||||
|   outputMustBe("NaN"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, PositiveInfinity) { | ||||
|   whenInputIs(std::numeric_limits<double>::infinity()); | ||||
|   outputMustBe("Infinity"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, NegativeInfinity) { | ||||
|   whenInputIs(-std::numeric_limits<double>::infinity()); | ||||
|   outputMustBe("-Infinity"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, Zero) { | ||||
|   whenInputIs(0); | ||||
|   outputMustBe("0.00"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_Rounding) { | ||||
|   whenInputIs(9.5, 0); | ||||
|   outputMustBe("10"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, ZeroDigits_NoRounding) { | ||||
|   whenInputIs(9.4, 0); | ||||
|   outputMustBe("9"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_Rounding) { | ||||
|   whenInputIs(9.95, 1); | ||||
|   outputMustBe("10.0"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, OneDigit_NoRounding) { | ||||
|   whenInputIs(9.94, 1); | ||||
|   outputMustBe("9.9"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_Rounding) { | ||||
|   whenInputIs(9.995, 2); | ||||
|   outputMustBe("10.00"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, TwoDigits_NoRounding) { | ||||
|   whenInputIs(9.994, 2); | ||||
|   outputMustBe("9.99"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_Rounding) { | ||||
|   whenInputIs(9.9995, 3); | ||||
|   outputMustBe("10.000"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, ThreeDigits_NoRounding) { | ||||
|   whenInputIs(9.9994, 3); | ||||
|   outputMustBe("9.999"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_Rounding) { | ||||
|   whenInputIs(9.99995, 4); | ||||
|   outputMustBe("10.0000"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, FourDigits_NoRounding) { | ||||
|   whenInputIs(9.99994, 4); | ||||
|   outputMustBe("9.9999"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_Rounding) { | ||||
|   whenInputIs(9.999995, 5); | ||||
|   outputMustBe("10.00000"); | ||||
| } | ||||
|  | ||||
| TEST_F(JsonWriter_WriteFloat_Tests, FiveDigits_NoRounding) { | ||||
|   whenInputIs(9.999994, 5); | ||||
|   outputMustBe("9.99999"); | ||||
| } | ||||
		Reference in New Issue
	
	Block a user