DeepCover Embedded Security in IoT: Public-key Secured Data Paths
Dependencies: MaximInterface
dtoa.h
00001 // Tencent is pleased to support the open source community by making RapidJSON available. 00002 // 00003 // Copyright (C) 2015 THL A29 Limited, a Tencent company, and Milo Yip. All rights reserved. 00004 // 00005 // Licensed under the MIT License (the "License"); you may not use this file except 00006 // in compliance with the License. You may obtain a copy of the License at 00007 // 00008 // http://opensource.org/licenses/MIT 00009 // 00010 // Unless required by applicable law or agreed to in writing, software distributed 00011 // under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR 00012 // CONDITIONS OF ANY KIND, either express or implied. See the License for the 00013 // specific language governing permissions and limitations under the License. 00014 00015 // This is a C++ header-only implementation of Grisu2 algorithm from the publication: 00016 // Loitsch, Florian. "Printing floating-point numbers quickly and accurately with 00017 // integers." ACM Sigplan Notices 45.6 (2010): 233-243. 00018 00019 #ifndef RAPIDJSON_DTOA_ 00020 #define RAPIDJSON_DTOA_ 00021 00022 #include "itoa.h" // GetDigitsLut() 00023 #include "diyfp.h" 00024 #include "ieee754.h" 00025 00026 RAPIDJSON_NAMESPACE_BEGIN 00027 namespace internal { 00028 00029 #ifdef __GNUC__ 00030 RAPIDJSON_DIAG_PUSH 00031 RAPIDJSON_DIAG_OFF(effc++) 00032 RAPIDJSON_DIAG_OFF(array-bounds) // some gcc versions generate wrong warnings https://gcc.gnu.org/bugzilla/show_bug.cgi?id=59124 00033 #endif 00034 00035 inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t ten_kappa, uint64_t wp_w) { 00036 while (rest < wp_w && delta - rest >= ten_kappa && 00037 (rest + ten_kappa < wp_w || /// closer 00038 wp_w - rest > rest + ten_kappa - wp_w)) { 00039 buffer[len - 1]--; 00040 rest += ten_kappa; 00041 } 00042 } 00043 00044 inline unsigned CountDecimalDigit32(uint32_t n) { 00045 // Simple pure C++ implementation was faster than __builtin_clz version in this situation. 00046 if (n < 10) return 1; 00047 if (n < 100) return 2; 00048 if (n < 1000) return 3; 00049 if (n < 10000) return 4; 00050 if (n < 100000) return 5; 00051 if (n < 1000000) return 6; 00052 if (n < 10000000) return 7; 00053 if (n < 100000000) return 8; 00054 // Will not reach 10 digits in DigitGen() 00055 //if (n < 1000000000) return 9; 00056 //return 10; 00057 return 9; 00058 } 00059 00060 inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K) { 00061 static const uint32_t kPow10[] = { 1, 10, 100, 1000, 10000, 100000, 1000000, 10000000, 100000000, 1000000000 }; 00062 const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); 00063 const DiyFp wp_w = Mp - W; 00064 uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e); 00065 uint64_t p2 = Mp.f & (one.f - 1); 00066 unsigned kappa = CountDecimalDigit32(p1); // kappa in [0, 9] 00067 *len = 0; 00068 00069 while (kappa > 0) { 00070 uint32_t d = 0; 00071 switch (kappa) { 00072 case 9: d = p1 / 100000000; p1 %= 100000000; break; 00073 case 8: d = p1 / 10000000; p1 %= 10000000; break; 00074 case 7: d = p1 / 1000000; p1 %= 1000000; break; 00075 case 6: d = p1 / 100000; p1 %= 100000; break; 00076 case 5: d = p1 / 10000; p1 %= 10000; break; 00077 case 4: d = p1 / 1000; p1 %= 1000; break; 00078 case 3: d = p1 / 100; p1 %= 100; break; 00079 case 2: d = p1 / 10; p1 %= 10; break; 00080 case 1: d = p1; p1 = 0; break; 00081 default:; 00082 } 00083 if (d || *len) 00084 buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d)); 00085 kappa--; 00086 uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2; 00087 if (tmp <= delta) { 00088 *K += kappa; 00089 GrisuRound(buffer, *len, delta, tmp, static_cast<uint64_t>(kPow10[kappa]) << -one.e, wp_w.f); 00090 return; 00091 } 00092 } 00093 00094 // kappa = 0 00095 for (;;) { 00096 p2 *= 10; 00097 delta *= 10; 00098 char d = static_cast<char>(p2 >> -one.e); 00099 if (d || *len) 00100 buffer[(*len)++] = static_cast<char>('0' + d); 00101 p2 &= one.f - 1; 00102 kappa--; 00103 if (p2 < delta) { 00104 *K += kappa; 00105 int index = -static_cast<int>(kappa); 00106 GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * (index < 9 ? kPow10[-static_cast<int>(kappa)] : 0)); 00107 return; 00108 } 00109 } 00110 } 00111 00112 inline void Grisu2(double value, char* buffer, int* length, int* K) { 00113 const DiyFp v(value); 00114 DiyFp w_m, w_p; 00115 v.NormalizedBoundaries(&w_m, &w_p); 00116 00117 const DiyFp c_mk = GetCachedPower(w_p.e, K); 00118 const DiyFp W = v.Normalize() * c_mk; 00119 DiyFp Wp = w_p * c_mk; 00120 DiyFp Wm = w_m * c_mk; 00121 Wm.f++; 00122 Wp.f--; 00123 DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); 00124 } 00125 00126 inline char* WriteExponent(int K, char* buffer) { 00127 if (K < 0) { 00128 *buffer++ = '-'; 00129 K = -K; 00130 } 00131 00132 if (K >= 100) { 00133 *buffer++ = static_cast<char>('0' + static_cast<char>(K / 100)); 00134 K %= 100; 00135 const char* d = GetDigitsLut() + K * 2; 00136 *buffer++ = d[0]; 00137 *buffer++ = d[1]; 00138 } 00139 else if (K >= 10) { 00140 const char* d = GetDigitsLut() + K * 2; 00141 *buffer++ = d[0]; 00142 *buffer++ = d[1]; 00143 } 00144 else 00145 *buffer++ = static_cast<char>('0' + static_cast<char>(K)); 00146 00147 return buffer; 00148 } 00149 00150 inline char* Prettify(char* buffer, int length, int k, int maxDecimalPlaces) { 00151 const int kk = length + k; // 10^(kk-1) <= v < 10^kk 00152 00153 if (0 <= k && kk <= 21) { 00154 // 1234e7 -> 12340000000 00155 for (int i = length; i < kk; i++) 00156 buffer[i] = '0'; 00157 buffer[kk] = '.'; 00158 buffer[kk + 1] = '0'; 00159 return &buffer[kk + 2]; 00160 } 00161 else if (0 < kk && kk <= 21) { 00162 // 1234e-2 -> 12.34 00163 std::memmove(&buffer[kk + 1], &buffer[kk], static_cast<size_t>(length - kk)); 00164 buffer[kk] = '.'; 00165 if (0 > k + maxDecimalPlaces) { 00166 // When maxDecimalPlaces = 2, 1.2345 -> 1.23, 1.102 -> 1.1 00167 // Remove extra trailing zeros (at least one) after truncation. 00168 for (int i = kk + maxDecimalPlaces; i > kk + 1; i--) 00169 if (buffer[i] != '0') 00170 return &buffer[i + 1]; 00171 return &buffer[kk + 2]; // Reserve one zero 00172 } 00173 else 00174 return &buffer[length + 1]; 00175 } 00176 else if (-6 < kk && kk <= 0) { 00177 // 1234e-6 -> 0.001234 00178 const int offset = 2 - kk; 00179 std::memmove(&buffer[offset], &buffer[0], static_cast<size_t>(length)); 00180 buffer[0] = '0'; 00181 buffer[1] = '.'; 00182 for (int i = 2; i < offset; i++) 00183 buffer[i] = '0'; 00184 if (length - kk > maxDecimalPlaces) { 00185 // When maxDecimalPlaces = 2, 0.123 -> 0.12, 0.102 -> 0.1 00186 // Remove extra trailing zeros (at least one) after truncation. 00187 for (int i = maxDecimalPlaces + 1; i > 2; i--) 00188 if (buffer[i] != '0') 00189 return &buffer[i + 1]; 00190 return &buffer[3]; // Reserve one zero 00191 } 00192 else 00193 return &buffer[length + offset]; 00194 } 00195 else if (kk < -maxDecimalPlaces) { 00196 // Truncate to zero 00197 buffer[0] = '0'; 00198 buffer[1] = '.'; 00199 buffer[2] = '0'; 00200 return &buffer[3]; 00201 } 00202 else if (length == 1) { 00203 // 1e30 00204 buffer[1] = 'e'; 00205 return WriteExponent(kk - 1, &buffer[2]); 00206 } 00207 else { 00208 // 1234e30 -> 1.234e33 00209 std::memmove(&buffer[2], &buffer[1], static_cast<size_t>(length - 1)); 00210 buffer[1] = '.'; 00211 buffer[length + 1] = 'e'; 00212 return WriteExponent(kk - 1, &buffer[0 + length + 2]); 00213 } 00214 } 00215 00216 inline char* dtoa(double value, char* buffer, int maxDecimalPlaces = 324) { 00217 RAPIDJSON_ASSERT(maxDecimalPlaces >= 1); 00218 Double d(value); 00219 if (d.IsZero()) { 00220 if (d.Sign()) 00221 *buffer++ = '-'; // -0.0, Issue #289 00222 buffer[0] = '0'; 00223 buffer[1] = '.'; 00224 buffer[2] = '0'; 00225 return &buffer[3]; 00226 } 00227 else { 00228 if (value < 0) { 00229 *buffer++ = '-'; 00230 value = -value; 00231 } 00232 int length, K; 00233 Grisu2(value, buffer, &length, &K); 00234 return Prettify(buffer, length, K, maxDecimalPlaces); 00235 } 00236 } 00237 00238 #ifdef __GNUC__ 00239 RAPIDJSON_DIAG_POP 00240 #endif 00241 00242 } // namespace internal 00243 RAPIDJSON_NAMESPACE_END 00244 00245 #endif // RAPIDJSON_DTOA_
Generated on Tue Jul 12 2022 12:06:48 by 1.7.2