DeepCover Embedded Security in IoT: Public-key Secured Data Paths
Dependencies: MaximInterface
strtod.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 #ifndef RAPIDJSON_STRTOD_ 00016 #define RAPIDJSON_STRTOD_ 00017 00018 #include "ieee754.h" 00019 #include "biginteger.h" 00020 #include "diyfp.h" 00021 #include "pow10.h" 00022 00023 RAPIDJSON_NAMESPACE_BEGIN 00024 namespace internal { 00025 00026 inline double FastPath(double significand, int exp) { 00027 if (exp < -308) 00028 return 0.0; 00029 else if (exp >= 0) 00030 return significand * internal::Pow10(exp); 00031 else 00032 return significand / internal::Pow10(-exp); 00033 } 00034 00035 inline double StrtodNormalPrecision(double d, int p) { 00036 if (p < -308) { 00037 // Prevent expSum < -308, making Pow10(p) = 0 00038 d = FastPath(d, -308); 00039 d = FastPath(d, p + 308); 00040 } 00041 else 00042 d = FastPath(d, p); 00043 return d; 00044 } 00045 00046 template <typename T> 00047 inline T Min3(T a, T b, T c) { 00048 T m = a; 00049 if (m > b) m = b; 00050 if (m > c) m = c; 00051 return m; 00052 } 00053 00054 inline int CheckWithinHalfULP(double b, const BigInteger& d, int dExp) { 00055 const Double db(b); 00056 const uint64_t bInt = db.IntegerSignificand(); 00057 const int bExp = db.IntegerExponent(); 00058 const int hExp = bExp - 1; 00059 00060 int dS_Exp2 = 0, dS_Exp5 = 0, bS_Exp2 = 0, bS_Exp5 = 0, hS_Exp2 = 0, hS_Exp5 = 0; 00061 00062 // Adjust for decimal exponent 00063 if (dExp >= 0) { 00064 dS_Exp2 += dExp; 00065 dS_Exp5 += dExp; 00066 } 00067 else { 00068 bS_Exp2 -= dExp; 00069 bS_Exp5 -= dExp; 00070 hS_Exp2 -= dExp; 00071 hS_Exp5 -= dExp; 00072 } 00073 00074 // Adjust for binary exponent 00075 if (bExp >= 0) 00076 bS_Exp2 += bExp; 00077 else { 00078 dS_Exp2 -= bExp; 00079 hS_Exp2 -= bExp; 00080 } 00081 00082 // Adjust for half ulp exponent 00083 if (hExp >= 0) 00084 hS_Exp2 += hExp; 00085 else { 00086 dS_Exp2 -= hExp; 00087 bS_Exp2 -= hExp; 00088 } 00089 00090 // Remove common power of two factor from all three scaled values 00091 int common_Exp2 = Min3(dS_Exp2, bS_Exp2, hS_Exp2); 00092 dS_Exp2 -= common_Exp2; 00093 bS_Exp2 -= common_Exp2; 00094 hS_Exp2 -= common_Exp2; 00095 00096 BigInteger dS = d; 00097 dS.MultiplyPow5(static_cast<unsigned>(dS_Exp5)) <<= static_cast<unsigned>(dS_Exp2); 00098 00099 BigInteger bS(bInt); 00100 bS.MultiplyPow5(static_cast<unsigned>(bS_Exp5)) <<= static_cast<unsigned>(bS_Exp2); 00101 00102 BigInteger hS(1); 00103 hS.MultiplyPow5(static_cast<unsigned>(hS_Exp5)) <<= static_cast<unsigned>(hS_Exp2); 00104 00105 BigInteger delta(0); 00106 dS.Difference(bS, &delta); 00107 00108 return delta.Compare(hS); 00109 } 00110 00111 inline bool StrtodFast(double d, int p, double* result) { 00112 // Use fast path for string-to-double conversion if possible 00113 // see http://www.exploringbinary.com/fast-path-decimal-to-floating-point-conversion/ 00114 if (p > 22 && p < 22 + 16) { 00115 // Fast Path Cases In Disguise 00116 d *= internal::Pow10(p - 22); 00117 p = 22; 00118 } 00119 00120 if (p >= -22 && p <= 22 && d <= 9007199254740991.0) { // 2^53 - 1 00121 *result = FastPath(d, p); 00122 return true; 00123 } 00124 else 00125 return false; 00126 } 00127 00128 // Compute an approximation and see if it is within 1/2 ULP 00129 inline bool StrtodDiyFp(const char* decimals, size_t length, size_t decimalPosition, int exp, double* result) { 00130 uint64_t significand = 0; 00131 size_t i = 0; // 2^64 - 1 = 18446744073709551615, 1844674407370955161 = 0x1999999999999999 00132 for (; i < length; i++) { 00133 if (significand > RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) || 00134 (significand == RAPIDJSON_UINT64_C2(0x19999999, 0x99999999) && decimals[i] > '5')) 00135 break; 00136 significand = significand * 10u + static_cast<unsigned>(decimals[i] - '0'); 00137 } 00138 00139 if (i < length && decimals[i] >= '5') // Rounding 00140 significand++; 00141 00142 size_t remaining = length - i; 00143 const unsigned kUlpShift = 3; 00144 const unsigned kUlp = 1 << kUlpShift; 00145 int64_t error = (remaining == 0) ? 0 : kUlp / 2; 00146 00147 DiyFp v(significand, 0); 00148 v = v.Normalize(); 00149 error <<= -v.e; 00150 00151 const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(i) + exp; 00152 00153 int actualExp; 00154 DiyFp cachedPower = GetCachedPower10(dExp, &actualExp); 00155 if (actualExp != dExp) { 00156 static const DiyFp kPow10[] = { 00157 DiyFp(RAPIDJSON_UINT64_C2(0xa0000000, 00000000), -60), // 10^1 00158 DiyFp(RAPIDJSON_UINT64_C2(0xc8000000, 00000000), -57), // 10^2 00159 DiyFp(RAPIDJSON_UINT64_C2(0xfa000000, 00000000), -54), // 10^3 00160 DiyFp(RAPIDJSON_UINT64_C2(0x9c400000, 00000000), -50), // 10^4 00161 DiyFp(RAPIDJSON_UINT64_C2(0xc3500000, 00000000), -47), // 10^5 00162 DiyFp(RAPIDJSON_UINT64_C2(0xf4240000, 00000000), -44), // 10^6 00163 DiyFp(RAPIDJSON_UINT64_C2(0x98968000, 00000000), -40) // 10^7 00164 }; 00165 int adjustment = dExp - actualExp - 1; 00166 RAPIDJSON_ASSERT(adjustment >= 0 && adjustment < 7); 00167 v = v * kPow10[adjustment]; 00168 if (length + static_cast<unsigned>(adjustment)> 19u) // has more digits than decimal digits in 64-bit 00169 error += kUlp / 2; 00170 } 00171 00172 v = v * cachedPower; 00173 00174 error += kUlp + (error == 0 ? 0 : 1); 00175 00176 const int oldExp = v.e; 00177 v = v.Normalize(); 00178 error <<= oldExp - v.e; 00179 00180 const unsigned effectiveSignificandSize = Double::EffectiveSignificandSize(64 + v.e); 00181 unsigned precisionSize = 64 - effectiveSignificandSize; 00182 if (precisionSize + kUlpShift >= 64) { 00183 unsigned scaleExp = (precisionSize + kUlpShift) - 63; 00184 v.f >>= scaleExp; 00185 v.e += scaleExp; 00186 error = (error >> scaleExp) + 1 + static_cast<int>(kUlp); 00187 precisionSize -= scaleExp; 00188 } 00189 00190 DiyFp rounded(v.f >> precisionSize, v.e + static_cast<int>(precisionSize)); 00191 const uint64_t precisionBits = (v.f & ((uint64_t(1) << precisionSize) - 1)) * kUlp; 00192 const uint64_t halfWay = (uint64_t(1) << (precisionSize - 1)) * kUlp; 00193 if (precisionBits >= halfWay + static_cast<unsigned>(error)) { 00194 rounded.f++; 00195 if (rounded.f & (DiyFp::kDpHiddenBit << 1)) { // rounding overflows mantissa (issue #340) 00196 rounded.f >>= 1; 00197 rounded.e++; 00198 } 00199 } 00200 00201 *result = rounded.ToDouble(); 00202 00203 return halfWay - static_cast<unsigned>(error) >= precisionBits || precisionBits >= halfWay + static_cast<unsigned>(error); 00204 } 00205 00206 inline double StrtodBigInteger(double approx, const char* decimals, size_t length, size_t decimalPosition, int exp) { 00207 const BigInteger dInt(decimals, length); 00208 const int dExp = static_cast<int>(decimalPosition) - static_cast<int>(length) + exp; 00209 Double a(approx); 00210 int cmp = CheckWithinHalfULP(a.Value(), dInt, dExp); 00211 if (cmp < 0) 00212 return a.Value(); // within half ULP 00213 else if (cmp == 0) { 00214 // Round towards even 00215 if (a.Significand() & 1) 00216 return a.NextPositiveDouble(); 00217 else 00218 return a.Value(); 00219 } 00220 else // adjustment 00221 return a.NextPositiveDouble(); 00222 } 00223 00224 inline double StrtodFullPrecision(double d, int p, const char* decimals, size_t length, size_t decimalPosition, int exp) { 00225 RAPIDJSON_ASSERT(d >= 0.0); 00226 RAPIDJSON_ASSERT(length >= 1); 00227 00228 double result; 00229 if (StrtodFast(d, p, &result)) 00230 return result; 00231 00232 // Trim leading zeros 00233 while (*decimals == '0' && length > 1) { 00234 length--; 00235 decimals++; 00236 decimalPosition--; 00237 } 00238 00239 // Trim trailing zeros 00240 while (decimals[length - 1] == '0' && length > 1) { 00241 length--; 00242 decimalPosition--; 00243 exp++; 00244 } 00245 00246 // Trim right-most digits 00247 const int kMaxDecimalDigit = 780; 00248 if (static_cast<int>(length) > kMaxDecimalDigit) { 00249 int delta = (static_cast<int>(length) - kMaxDecimalDigit); 00250 exp += delta; 00251 decimalPosition -= static_cast<unsigned>(delta); 00252 length = kMaxDecimalDigit; 00253 } 00254 00255 // If too small, underflow to zero 00256 if (int(length) + exp < -324) 00257 return 0.0; 00258 00259 if (StrtodDiyFp(decimals, length, decimalPosition, exp, &result)) 00260 return result; 00261 00262 // Use approximation from StrtodDiyFp and make adjustment with BigInteger comparison 00263 return StrtodBigInteger(result, decimals, length, decimalPosition, exp); 00264 } 00265 00266 } // namespace internal 00267 RAPIDJSON_NAMESPACE_END 00268 00269 #endif // RAPIDJSON_STRTOD_
Generated on Tue Jul 12 2022 12:06:49 by 1.7.2