mirror of
				https://github.com/eledio-devices/thirdparty-ArduinoJson.git
				synced 2025-10-31 16:14:11 +01:00 
			
		
		
		
	Fixed "constant exceeds range of float [-Woverflow]" (issue #544)
This commit is contained in:
		| @@ -5,6 +5,9 @@ HEAD | |||||||
| ---- | ---- | ||||||
|  |  | ||||||
| * Removed dependency on `PGM_P` as Particle 0.6.2 doesn't define it (issue #546) | * Removed dependency on `PGM_P` as Particle 0.6.2 doesn't define it (issue #546) | ||||||
|  | * Fixed warning "dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]" | ||||||
|  | * Fixed warning "floating constant exceeds range of 'float' [-Woverflow]" (issue #544) | ||||||
|  | * Removed `ARDUINOJSON_DOUBLE_IS_64BITS` as it became useless. | ||||||
|  |  | ||||||
| v5.11.0 | v5.11.0 | ||||||
| ------- | ------- | ||||||
|   | |||||||
| @@ -148,16 +148,6 @@ | |||||||
| #define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 | #define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 | ||||||
| #endif | #endif | ||||||
|  |  | ||||||
| // how many bits in a double |  | ||||||
| #ifndef ARDUINOJSON_DOUBLE_IS_64BITS |  | ||||||
| #if /*GCC*/ (defined(__SIZEOF_DOUBLE__) && __SIZEOF_DOUBLE__ < 8) || \ |  | ||||||
|     /*IAR*/ (defined(__DOUBLE__) && __DOUBLE__ < 64) |  | ||||||
| #define ARDUINOJSON_DOUBLE_IS_64BITS 0 |  | ||||||
| #else |  | ||||||
| #define ARDUINOJSON_DOUBLE_IS_64BITS 1  // by default support 64-bit |  | ||||||
| #endif |  | ||||||
| #endif |  | ||||||
|  |  | ||||||
| #if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 | #if ARDUINOJSON_USE_LONG_LONG && ARDUINOJSON_USE_INT64 | ||||||
| #error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together | #error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together | ||||||
| #endif | #endif | ||||||
|   | |||||||
| @@ -8,92 +8,35 @@ | |||||||
| #pragma once | #pragma once | ||||||
|  |  | ||||||
| #include "../Configuration.hpp" | #include "../Configuration.hpp" | ||||||
|  | #include "../TypeTraits/FloatTraits.hpp" | ||||||
|  |  | ||||||
| namespace ArduinoJson { | namespace ArduinoJson { | ||||||
| namespace Polyfills { | namespace Polyfills { | ||||||
| template <typename T> | template <typename T> | ||||||
| int16_t normalize(T& value) { | int16_t normalize(T& value) { | ||||||
|  |   using namespace TypeTraits; | ||||||
|   int16_t powersOf10 = 0; |   int16_t powersOf10 = 0; | ||||||
|  |  | ||||||
|  |   int8_t index = sizeof(T) == 8 ? 8 : 5; | ||||||
|  |   int bit = 1 << index; | ||||||
|  |  | ||||||
|   if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { |   if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { | ||||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS |     for (; index >= 0; index--) { | ||||||
|     if (value >= 1e256) { |       if (value >= FloatTraits<T>::positiveBinaryPowerOfTen(index)) { | ||||||
|       value /= 1e256; |         value *= FloatTraits<T>::negativeBinaryPowerOfTen(index); | ||||||
|       powersOf10 = int16_t(powersOf10 + 256); |         powersOf10 = int16_t(powersOf10 + bit); | ||||||
|     } |       } | ||||||
|     if (value >= 1e128) { |       bit >>= 1; | ||||||
|       value /= 1e128; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 128); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e64) { |  | ||||||
|       value /= 1e64; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 64); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|     if (value >= 1e32) { |  | ||||||
|       value /= 1e32; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 32); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e16) { |  | ||||||
|       value /= 1e16; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 16); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e8) { |  | ||||||
|       value /= 1e8; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 8); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e4) { |  | ||||||
|       value /= 1e4; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 4); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e2) { |  | ||||||
|       value /= 1e2; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 2); |  | ||||||
|     } |  | ||||||
|     if (value >= 1e1) { |  | ||||||
|       value /= 1e1; |  | ||||||
|       powersOf10 = int16_t(powersOf10 + 1); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { |   if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { | ||||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS |     for (; index >= 0; index--) { | ||||||
|     if (value < 1e-255) { |       if (value < FloatTraits<T>::negativeBinaryPowerOfTenPlusOne(index)) { | ||||||
|       value *= 1e256; |         value *= FloatTraits<T>::positiveBinaryPowerOfTen(index); | ||||||
|       powersOf10 = int16_t(powersOf10 - 256); |         powersOf10 = int16_t(powersOf10 - bit); | ||||||
|     } |       } | ||||||
|     if (value < 1e-127) { |       bit >>= 1; | ||||||
|       value *= 1e128; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 128); |  | ||||||
|     } |  | ||||||
|     if (value < 1e-63) { |  | ||||||
|       value *= 1e64; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 64); |  | ||||||
|     } |  | ||||||
| #endif |  | ||||||
|     if (value < 1e-31) { |  | ||||||
|       value *= 1e32; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 32); |  | ||||||
|     } |  | ||||||
|     if (value < 1e-15) { |  | ||||||
|       value *= 1e16; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 16); |  | ||||||
|     } |  | ||||||
|     if (value < 1e-7) { |  | ||||||
|       value *= 1e8; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 8); |  | ||||||
|     } |  | ||||||
|     if (value < 1e-3) { |  | ||||||
|       value *= 1e4; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 4); |  | ||||||
|     } |  | ||||||
|     if (value < 1e-1) { |  | ||||||
|       value *= 1e2; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 2); |  | ||||||
|     } |  | ||||||
|     if (value < 1e0) { |  | ||||||
|       value *= 1e1; |  | ||||||
|       powersOf10 = int16_t(powersOf10 - 1); |  | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -18,7 +18,6 @@ namespace TypeTraits { | |||||||
| template <typename T, size_t = sizeof(T)> | template <typename T, size_t = sizeof(T)> | ||||||
| struct FloatTraits {}; | struct FloatTraits {}; | ||||||
|  |  | ||||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS |  | ||||||
| template <typename T> | template <typename T> | ||||||
| struct FloatTraits<T, 8 /*64bits*/> { | struct FloatTraits<T, 8 /*64bits*/> { | ||||||
|   typedef int64_t mantissa_type; |   typedef int64_t mantissa_type; | ||||||
| @@ -31,29 +30,65 @@ struct FloatTraits<T, 8 /*64bits*/> { | |||||||
|  |  | ||||||
|   template <typename TExponent> |   template <typename TExponent> | ||||||
|   static T make_float(T m, TExponent e) { |   static T make_float(T m, TExponent e) { | ||||||
|     if (e >= 0) |     if (e > 0) { | ||||||
|       return m * (e & 1 ? 1e1 : 1) * (e & 2 ? 1e2 : 1) * (e & 4 ? 1e4 : 1) * |       for (uint8_t index = 0; e != 0; index++) { | ||||||
|              (e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) * |         if (e & 1) m *= positiveBinaryPowerOfTen(index); | ||||||
|              (e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) * |         e >>= 1; | ||||||
|              (e & 256 ? 1e256 : 1); |       } | ||||||
|     e = TExponent(-e); |     } else { | ||||||
|     return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) * |       e = TExponent(-e); | ||||||
|            (e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) * |       for (uint8_t index = 0; e != 0; index++) { | ||||||
|            (e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) * |         if (e & 1) m *= negativeBinaryPowerOfTen(index); | ||||||
|            (e & 256 ? 1e-256 : 1); |         e >>= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return m; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T positiveBinaryPowerOfTen(int index) { | ||||||
|  |     static T factors[] = { | ||||||
|  |         1e1, 1e2, 1e4, 1e8, 1e16, 1e32, | ||||||
|  |         // workaround to support platforms with single precision literals | ||||||
|  |         forge(0x4D384F03, 0xE93FF9F5), forge(0x5A827748, 0xF9301D32), | ||||||
|  |         forge(0x75154FDD, 0x7F73BF3C)}; | ||||||
|  |     return factors[index]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T negativeBinaryPowerOfTen(int index) { | ||||||
|  |     static T factors[] = { | ||||||
|  |         1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32, | ||||||
|  |         // workaround to support platforms with single precision literals | ||||||
|  |         forge(0x32A50FFD, 0x44F4A73D), forge(0x255BBA08, 0xCF8C979D), | ||||||
|  |         forge(0x0AC80628, 0x64AC6F43)}; | ||||||
|  |     return factors[index]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T negativeBinaryPowerOfTenPlusOne(int index) { | ||||||
|  |     static T factors[] = { | ||||||
|  |         1e0, 1e-1, 1e-3, 1e-7, 1e-15, 1e-31, | ||||||
|  |         // workaround to support platforms with single precision literals | ||||||
|  |         forge(0x32DA53FC, 0x9631D10D), forge(0x25915445, 0x81B7DEC2), | ||||||
|  |         forge(0x0AFE07B2, 0x7DD78B14)}; | ||||||
|  |     return factors[index]; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static T nan() { |   static T nan() { | ||||||
|     uint64_t x = uint64_t(0x7ff8) << 48; |     return forge(0x7ff80000, 0x00000000); | ||||||
|     return *reinterpret_cast<T*>(&x); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static T inf() { |   static T inf() { | ||||||
|     uint64_t x = uint64_t(0x7ff0) << 48; |     return forge(0x7ff00000, 0x00000000); | ||||||
|     return *reinterpret_cast<T*>(&x); |   } | ||||||
|  |  | ||||||
|  |   static T forge(uint32_t msb, uint32_t lsb) { | ||||||
|  |     union { | ||||||
|  |       uint64_t integerBits; | ||||||
|  |       T floatBits; | ||||||
|  |     }; | ||||||
|  |     integerBits = (uint64_t(msb) << 32) | lsb; | ||||||
|  |     return floatBits; | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| #endif |  | ||||||
|  |  | ||||||
| template <typename T> | template <typename T> | ||||||
| struct FloatTraits<T, 4 /*32bits*/> { | struct FloatTraits<T, 4 /*32bits*/> { | ||||||
| @@ -67,22 +102,51 @@ struct FloatTraits<T, 4 /*32bits*/> { | |||||||
|  |  | ||||||
|   template <typename TExponent> |   template <typename TExponent> | ||||||
|   static T make_float(T m, TExponent e) { |   static T make_float(T m, TExponent e) { | ||||||
|     if (e > 0) |     if (e > 0) { | ||||||
|       return m * (e & 1 ? 1e1f : 1) * (e & 2 ? 1e2f : 1) * (e & 4 ? 1e4f : 1) * |       for (uint8_t index = 0; e != 0; index++) { | ||||||
|              (e & 8 ? 1e8f : 1) * (e & 16 ? 1e16f : 1) * (e & 32 ? 1e32f : 1); |         if (e & 1) m *= positiveBinaryPowerOfTen(index); | ||||||
|     e = -e; |         e >>= 1; | ||||||
|     return m * (e & 1 ? 1e-1f : 1) * (e & 2 ? 1e-2f : 1) * (e & 4 ? 1e-4f : 1) * |       } | ||||||
|            (e & 8 ? 1e-8f : 1) * (e & 16 ? 1e-16f : 1) * (e & 32 ? 1e-32f : 1); |     } else { | ||||||
|  |       e = -e; | ||||||
|  |       for (uint8_t index = 0; e != 0; index++) { | ||||||
|  |         if (e & 1) m *= negativeBinaryPowerOfTen(index); | ||||||
|  |         e >>= 1; | ||||||
|  |       } | ||||||
|  |     } | ||||||
|  |     return m; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T positiveBinaryPowerOfTen(int index) { | ||||||
|  |     static T factors[] = {1e1f, 1e2f, 1e4f, 1e8f, 1e16f, 1e32f}; | ||||||
|  |     return factors[index]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T negativeBinaryPowerOfTen(int index) { | ||||||
|  |     static T factors[] = {1e-1f, 1e-2f, 1e-4f, 1e-8f, 1e-16f, 1e-32f}; | ||||||
|  |     return factors[index]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T negativeBinaryPowerOfTenPlusOne(int index) { | ||||||
|  |     static T factors[] = {1e0f, 1e-1f, 1e-3f, 1e-7f, 1e-15f, 1e-31f}; | ||||||
|  |     return factors[index]; | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   static T forge(uint32_t bits) { | ||||||
|  |     union { | ||||||
|  |       uint32_t integerBits; | ||||||
|  |       T floatBits; | ||||||
|  |     }; | ||||||
|  |     integerBits = bits; | ||||||
|  |     return floatBits; | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static T nan() { |   static T nan() { | ||||||
|     uint32_t x = 0x7fc00000; |     return forge(0x7fc00000); | ||||||
|     return *reinterpret_cast<T*>(&x); |  | ||||||
|   } |   } | ||||||
|  |  | ||||||
|   static T inf() { |   static T inf() { | ||||||
|     uint32_t x = 0x7f800000; |     return forge(0x7f800000); | ||||||
|     return *reinterpret_cast<T*>(&x); |  | ||||||
|   } |   } | ||||||
| }; | }; | ||||||
| } | } | ||||||
|   | |||||||
| @@ -19,13 +19,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") | |||||||
| 		-Wformat=2 | 		-Wformat=2 | ||||||
| 		-Winit-self | 		-Winit-self | ||||||
| 		-Wmissing-include-dirs | 		-Wmissing-include-dirs | ||||||
| 		-Wparentheses |  | ||||||
| 		-Wnon-virtual-dtor | 		-Wnon-virtual-dtor | ||||||
| 		-Wold-style-cast | 		-Wold-style-cast | ||||||
| 		-Woverloaded-virtual | 		-Woverloaded-virtual | ||||||
|  | 		-Wparentheses | ||||||
| 		-Wredundant-decls | 		-Wredundant-decls | ||||||
| 		-Wshadow | 		-Wshadow | ||||||
| 		-Wsign-promo | 		-Wsign-promo | ||||||
|  | 		-Wstrict-aliasing | ||||||
| 		-Wstrict-overflow=5 | 		-Wstrict-overflow=5 | ||||||
| 		-Wundef | 		-Wundef | ||||||
| 	) | 	) | ||||||
|   | |||||||
| @@ -10,5 +10,12 @@ add_executable(IntegrationTests | |||||||
| 	round_trip.cpp | 	round_trip.cpp | ||||||
| ) | ) | ||||||
|  |  | ||||||
|  | if(CMAKE_CXX_COMPILER_ID MATCHES "GNU") | ||||||
|  | 	target_compile_options(IntegrationTests | ||||||
|  | 		PUBLIC | ||||||
|  | 		-fsingle-precision-constant # issue 544 | ||||||
|  | 	) | ||||||
|  | endif() | ||||||
|  |  | ||||||
| target_link_libraries(IntegrationTests catch) | target_link_libraries(IntegrationTests catch) | ||||||
| add_test(IntegrationTests IntegrationTests) | add_test(IntegrationTests IntegrationTests) | ||||||
|   | |||||||
| @@ -8,6 +8,7 @@ | |||||||
| add_executable(PolyfillsTests  | add_executable(PolyfillsTests  | ||||||
| 	isFloat.cpp | 	isFloat.cpp | ||||||
| 	isInteger.cpp | 	isInteger.cpp | ||||||
|  | 	normalize.cpp | ||||||
| 	parseFloat.cpp | 	parseFloat.cpp | ||||||
| 	parseInteger.cpp | 	parseInteger.cpp | ||||||
| ) | ) | ||||||
|   | |||||||
							
								
								
									
										43
									
								
								test/Polyfills/normalize.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										43
									
								
								test/Polyfills/normalize.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,43 @@ | |||||||
|  | // Copyright Benoit Blanchon 2014-2017 | ||||||
|  | // MIT License | ||||||
|  | // | ||||||
|  | // Arduino JSON library | ||||||
|  | // https://bblanchon.github.io/ArduinoJson/ | ||||||
|  | // If you like this project, please add a star! | ||||||
|  |  | ||||||
|  | #include <ArduinoJson/Polyfills/normalize.hpp> | ||||||
|  | #include <catch.hpp> | ||||||
|  |  | ||||||
|  | using namespace ArduinoJson::Polyfills; | ||||||
|  |  | ||||||
|  | TEST_CASE("normalize<double>()") { | ||||||
|  |   SECTION("1.7976931348623157E+308") { | ||||||
|  |     double value = 1.7976931348623157E+308; | ||||||
|  |     int exp = normalize(value); | ||||||
|  |     REQUIRE(value == Approx(1.7976931348623157)); | ||||||
|  |     REQUIRE(exp == 308); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("4.94065645841247e-324") { | ||||||
|  |     double value = 4.94065645841247e-324; | ||||||
|  |     int exp = normalize(value); | ||||||
|  |     REQUIRE(value == Approx(4.94065645841247)); | ||||||
|  |     REQUIRE(exp == -324); | ||||||
|  |   } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | TEST_CASE("normalize<float>()") { | ||||||
|  |   SECTION("3.4E+38") { | ||||||
|  |     float value = 3.4E+38f; | ||||||
|  |     int exp = normalize(value); | ||||||
|  |     REQUIRE(value == Approx(3.4f)); | ||||||
|  |     REQUIRE(exp == 38); | ||||||
|  |   } | ||||||
|  |  | ||||||
|  |   SECTION("1.17549435e−38") { | ||||||
|  |     float value = 1.17549435e-38f; | ||||||
|  |     int exp = normalize(value); | ||||||
|  |     REQUIRE(value == Approx(1.17549435)); | ||||||
|  |     REQUIRE(exp == -38); | ||||||
|  |   } | ||||||
|  | } | ||||||
		Reference in New Issue
	
	Block a user