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) | ||||
| * 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 | ||||
| ------- | ||||
|   | ||||
| @@ -148,16 +148,6 @@ | ||||
| #define ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD 1e-5 | ||||
| #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 | ||||
| #error ARDUINOJSON_USE_LONG_LONG and ARDUINOJSON_USE_INT64 cannot be set together | ||||
| #endif | ||||
|   | ||||
| @@ -8,92 +8,35 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include "../Configuration.hpp" | ||||
| #include "../TypeTraits/FloatTraits.hpp" | ||||
|  | ||||
| namespace ArduinoJson { | ||||
| namespace Polyfills { | ||||
| template <typename T> | ||||
| int16_t normalize(T& value) { | ||||
|   using namespace TypeTraits; | ||||
|   int16_t powersOf10 = 0; | ||||
|  | ||||
|   int8_t index = sizeof(T) == 8 ? 8 : 5; | ||||
|   int bit = 1 << index; | ||||
|  | ||||
|   if (value >= ARDUINOJSON_POSITIVE_EXPONENTIATION_THRESHOLD) { | ||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS | ||||
|     if (value >= 1e256) { | ||||
|       value /= 1e256; | ||||
|       powersOf10 = int16_t(powersOf10 + 256); | ||||
|     } | ||||
|     if (value >= 1e128) { | ||||
|       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); | ||||
|     for (; index >= 0; index--) { | ||||
|       if (value >= FloatTraits<T>::positiveBinaryPowerOfTen(index)) { | ||||
|         value *= FloatTraits<T>::negativeBinaryPowerOfTen(index); | ||||
|         powersOf10 = int16_t(powersOf10 + bit); | ||||
|       } | ||||
|       bit >>= 1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if (value > 0 && value <= ARDUINOJSON_NEGATIVE_EXPONENTIATION_THRESHOLD) { | ||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS | ||||
|     if (value < 1e-255) { | ||||
|       value *= 1e256; | ||||
|       powersOf10 = int16_t(powersOf10 - 256); | ||||
|     } | ||||
|     if (value < 1e-127) { | ||||
|       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); | ||||
|     for (; index >= 0; index--) { | ||||
|       if (value < FloatTraits<T>::negativeBinaryPowerOfTenPlusOne(index)) { | ||||
|         value *= FloatTraits<T>::positiveBinaryPowerOfTen(index); | ||||
|         powersOf10 = int16_t(powersOf10 - bit); | ||||
|       } | ||||
|       bit >>= 1; | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   | ||||
| @@ -18,7 +18,6 @@ namespace TypeTraits { | ||||
| template <typename T, size_t = sizeof(T)> | ||||
| struct FloatTraits {}; | ||||
|  | ||||
| #if ARDUINOJSON_DOUBLE_IS_64BITS | ||||
| template <typename T> | ||||
| struct FloatTraits<T, 8 /*64bits*/> { | ||||
|   typedef int64_t mantissa_type; | ||||
| @@ -31,29 +30,65 @@ struct FloatTraits<T, 8 /*64bits*/> { | ||||
|  | ||||
|   template <typename TExponent> | ||||
|   static T make_float(T m, TExponent e) { | ||||
|     if (e >= 0) | ||||
|       return m * (e & 1 ? 1e1 : 1) * (e & 2 ? 1e2 : 1) * (e & 4 ? 1e4 : 1) * | ||||
|              (e & 8 ? 1e8 : 1) * (e & 16 ? 1e16 : 1) * (e & 32 ? 1e32 : 1) * | ||||
|              (e & 64 ? 1e64 : 1) * (e & 128 ? 1e128 : 1) * | ||||
|              (e & 256 ? 1e256 : 1); | ||||
|     e = TExponent(-e); | ||||
|     return m * (e & 1 ? 1e-1 : 1) * (e & 2 ? 1e-2 : 1) * (e & 4 ? 1e-4 : 1) * | ||||
|            (e & 8 ? 1e-8 : 1) * (e & 16 ? 1e-16 : 1) * (e & 32 ? 1e-32 : 1) * | ||||
|            (e & 64 ? 1e-64 : 1) * (e & 128 ? 1e-128 : 1) * | ||||
|            (e & 256 ? 1e-256 : 1); | ||||
|     if (e > 0) { | ||||
|       for (uint8_t index = 0; e != 0; index++) { | ||||
|         if (e & 1) m *= positiveBinaryPowerOfTen(index); | ||||
|         e >>= 1; | ||||
|       } | ||||
|     } else { | ||||
|       e = TExponent(-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[] = { | ||||
|         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() { | ||||
|     uint64_t x = uint64_t(0x7ff8) << 48; | ||||
|     return *reinterpret_cast<T*>(&x); | ||||
|     return forge(0x7ff80000, 0x00000000); | ||||
|   } | ||||
|  | ||||
|   static T inf() { | ||||
|     uint64_t x = uint64_t(0x7ff0) << 48; | ||||
|     return *reinterpret_cast<T*>(&x); | ||||
|     return forge(0x7ff00000, 0x00000000); | ||||
|   } | ||||
|  | ||||
|   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> | ||||
| struct FloatTraits<T, 4 /*32bits*/> { | ||||
| @@ -67,22 +102,51 @@ struct FloatTraits<T, 4 /*32bits*/> { | ||||
|  | ||||
|   template <typename TExponent> | ||||
|   static T make_float(T m, TExponent e) { | ||||
|     if (e > 0) | ||||
|       return m * (e & 1 ? 1e1f : 1) * (e & 2 ? 1e2f : 1) * (e & 4 ? 1e4f : 1) * | ||||
|              (e & 8 ? 1e8f : 1) * (e & 16 ? 1e16f : 1) * (e & 32 ? 1e32f : 1); | ||||
|     e = -e; | ||||
|     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); | ||||
|     if (e > 0) { | ||||
|       for (uint8_t index = 0; e != 0; index++) { | ||||
|         if (e & 1) m *= positiveBinaryPowerOfTen(index); | ||||
|         e >>= 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() { | ||||
|     uint32_t x = 0x7fc00000; | ||||
|     return *reinterpret_cast<T*>(&x); | ||||
|     return forge(0x7fc00000); | ||||
|   } | ||||
|  | ||||
|   static T inf() { | ||||
|     uint32_t x = 0x7f800000; | ||||
|     return *reinterpret_cast<T*>(&x); | ||||
|     return forge(0x7f800000); | ||||
|   } | ||||
| }; | ||||
| } | ||||
|   | ||||
| @@ -19,13 +19,14 @@ if(CMAKE_CXX_COMPILER_ID MATCHES "(GNU|Clang)") | ||||
| 		-Wformat=2 | ||||
| 		-Winit-self | ||||
| 		-Wmissing-include-dirs | ||||
| 		-Wparentheses | ||||
| 		-Wnon-virtual-dtor | ||||
| 		-Wold-style-cast | ||||
| 		-Woverloaded-virtual | ||||
| 		-Wparentheses | ||||
| 		-Wredundant-decls | ||||
| 		-Wshadow | ||||
| 		-Wsign-promo | ||||
| 		-Wstrict-aliasing | ||||
| 		-Wstrict-overflow=5 | ||||
| 		-Wundef | ||||
| 	) | ||||
|   | ||||
| @@ -10,5 +10,12 @@ add_executable(IntegrationTests | ||||
| 	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) | ||||
| add_test(IntegrationTests IntegrationTests) | ||||
|   | ||||
| @@ -8,6 +8,7 @@ | ||||
| add_executable(PolyfillsTests  | ||||
| 	isFloat.cpp | ||||
| 	isInteger.cpp | ||||
| 	normalize.cpp | ||||
| 	parseFloat.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