DeepCover Embedded Security in IoT: Public-key Secured Data Paths

Dependencies:   MaximInterface

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers strtod.h Source File

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_