1 /* 2 * Copyright (c) 2024-2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef ES2PANDA_UTIL_INCLUDE_DTOA_HELPER_H 17 #define ES2PANDA_UTIL_INCLUDE_DTOA_HELPER_H 18 19 #include <cstdint> 20 #include <cstddef> 21 #include <array> 22 #include "globals.h" 23 #include "util/es2pandaMacros.h" 24 25 // Almost copy of ets_runtime/ecmascript/base/dtoa_helper.h 26 27 namespace ark::es2panda::util { 28 29 // Helper defines for double 30 constexpr int DOUBLE_MAX_PRECISION = 17; 31 constexpr int FLOAT_MAX_PRECISION = 9; 32 constexpr int DOUBLE_EXPONENT_BIAS = 0x3FF; 33 constexpr size_t DOUBLE_SIGNIFICAND_SIZE = 52; 34 constexpr uint64_t DOUBLE_SIGN_MASK = 0x8000000000000000ULL; 35 constexpr size_t DOUBLE_EXPONENT_SIZE = 11; 36 constexpr int DOUBLE_EXPONENT_MAX = 0x7FFULL; 37 constexpr uint64_t DOUBLE_EXPONENT_MASK = 0x7FFULL << DOUBLE_SIGNIFICAND_SIZE; 38 constexpr uint64_t DOUBLE_SIGNIFICAND_MASK = 0x000FFFFFFFFFFFFFULL; 39 constexpr uint64_t DOUBLE_HIDDEN_BIT = 1ULL << DOUBLE_SIGNIFICAND_SIZE; 40 41 class DtoaHelper { 42 public: DtoaHelper(char * buffer)43 explicit DtoaHelper(char *buffer) : buffer_(buffer) {} 44 void Dtoa(double value); 45 GetPoint()46 int GetPoint() 47 { 48 return point_; 49 } 50 GetDigits()51 int GetDigits() 52 { 53 return length_; 54 } 55 56 private: 57 static constexpr int CACHED_POWERS_OFFSET = 348; 58 static constexpr double D_1_LOG2_10 = 0x1.34413509f79ffp-2; // 1 / lg(10) 59 static constexpr int Q = -61; 60 static constexpr int INDEX = 20; 61 static constexpr int MIN_DECIMAL_EXPONENT = -348; 62 static constexpr auto POW10 = std::array {1ULL, 63 10ULL, 64 100ULL, 65 1000ULL, 66 10000ULL, 67 100000ULL, 68 1000000ULL, 69 10000000ULL, 70 100000000ULL, 71 1000000000ULL, 72 10000000000ULL, 73 100000000000ULL, 74 1000000000000ULL, 75 10000000000000ULL, 76 100000000000000ULL, 77 1000000000000000ULL, 78 10000000000000000ULL, 79 100000000000000000ULL, 80 1000000000000000000ULL, 81 10000000000000000000ULL}; 82 83 static constexpr uint32_t TEN = 10; 84 static constexpr uint32_t TEN2POW = 100; 85 static constexpr uint32_t TEN3POW = 1000; 86 static constexpr uint32_t TEN4POW = 10000; 87 static constexpr uint32_t TEN5POW = 100000; 88 static constexpr uint32_t TEN6POW = 1000000; 89 static constexpr uint32_t TEN7POW = 10000000; 90 static constexpr uint32_t TEN8POW = 100000000; 91 92 // DiyFp is a floating-point number type, consists of a uint64 significand and one integer exponent. 93 class DiyFp { 94 public: DiyFp()95 DiyFp() : f_(), e_() {} DiyFp(uint64_t fp,int exp)96 DiyFp(uint64_t fp, int exp) : f_(fp), e_(exp) {} 97 DiyFp(double d)98 explicit DiyFp(double d) 99 { 100 union { 101 double d; 102 uint64_t u64; 103 } u = {d}; 104 105 int biasedE = 106 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) 107 static_cast<int>((u.u64 & DOUBLE_EXPONENT_MASK) >> DOUBLE_SIGNIFICAND_SIZE); 108 // NOLINTNEXTLINE(cppcoreguidelines-pro-type-union-access) 109 uint64_t significand = (u.u64 & DOUBLE_SIGNIFICAND_MASK); 110 if (biasedE != 0) { 111 f_ = significand + DOUBLE_HIDDEN_BIT; 112 e_ = biasedE - DP_EXPONENT_BIAS; 113 } else { 114 f_ = significand; 115 e_ = DP_MIN_EXPONENT + 1; 116 } 117 } 118 119 DiyFp operator-(const DiyFp &rhs) const 120 { 121 return DiyFp(f_ - rhs.f_, e_); 122 } 123 124 DiyFp operator*(const DiyFp &rhs) const 125 { 126 constexpr uint64_t M32 = UINT32_MAX; 127 const uint64_t a = f_ >> BITS_PER_UINT32; 128 const uint64_t b = f_ & M32; 129 const uint64_t c = rhs.f_ >> BITS_PER_UINT32; 130 const uint64_t d = rhs.f_ & M32; 131 const uint64_t ac = a * c; 132 const uint64_t bc = b * c; 133 const uint64_t ad = a * d; 134 const uint64_t bd = b * d; 135 uint64_t tmp = (bd >> BITS_PER_UINT32) + (ad & M32) + (bc & M32); 136 tmp += 1U << ROUND_BITS; // mult_round 137 return DiyFp(ac + (ad >> BITS_PER_UINT32) + (bc >> BITS_PER_UINT32) + (tmp >> BITS_PER_UINT32), 138 e_ + rhs.e_ + BITS_PER_UINT64); 139 } 140 Normalize()141 DiyFp Normalize() const 142 { 143 DiyFp res = *this; 144 while ((res.f_ & DOUBLE_HIDDEN_BIT) == 0) { 145 res.f_ <<= 1U; 146 res.e_--; 147 } 148 res.f_ <<= (DIY_SIGNIFICAND_SIZE - DOUBLE_SIGNIFICAND_SIZE - 1); 149 res.e_ = res.e_ - (DIY_SIGNIFICAND_SIZE - DOUBLE_SIGNIFICAND_SIZE - 1); 150 return res; 151 } 152 NormalizeBoundary()153 DiyFp NormalizeBoundary() const 154 { 155 DiyFp res = *this; 156 while ((res.f_ & (DOUBLE_HIDDEN_BIT << 1U)) == 0) { 157 res.f_ <<= 1U; 158 res.e_--; 159 } 160 res.f_ <<= (DIY_SIGNIFICAND_SIZE - DOUBLE_SIGNIFICAND_SIZE - 2); // 2: parameter 161 res.e_ = res.e_ - (DIY_SIGNIFICAND_SIZE - DOUBLE_SIGNIFICAND_SIZE - 2); // 2: parameter 162 return res; 163 } 164 NormalizedBoundaries(DiyFp * minus,DiyFp * plus)165 void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const 166 { 167 DiyFp pl = DiyFp((f_ << 1U) + 1, e_ - 1).NormalizeBoundary(); 168 DiyFp mi = (f_ == DOUBLE_HIDDEN_BIT) ? DiyFp((f_ << 2U) - 1, e_ - 2) 169 : DiyFp((f_ << 1U) - 1, e_ - 1); // 2: parameter 170 ES2PANDA_ASSERT(mi.e_ >= pl.e_); 171 mi.f_ <<= static_cast<uint32_t>(mi.e_ - pl.e_); 172 mi.e_ = pl.e_; 173 *plus = pl; 174 *minus = mi; 175 } 176 177 static constexpr uint32_t ROUND_BITS = BITS_PER_UINT32 - 1; 178 static constexpr uint32_t DIY_SIGNIFICAND_SIZE = BITS_PER_UINT64; 179 static constexpr int32_t DP_EXPONENT_BIAS = DOUBLE_EXPONENT_BIAS + DOUBLE_SIGNIFICAND_SIZE; 180 static constexpr int32_t DP_MAX_EXPONENT = DOUBLE_EXPONENT_MAX - DP_EXPONENT_BIAS; 181 static constexpr int32_t DP_MIN_EXPONENT = -DP_EXPONENT_BIAS; 182 static constexpr int32_t DP_DENORMAL_EXPONENT = -DP_EXPONENT_BIAS + 1; 183 184 private: 185 uint64_t f_; 186 int e_; 187 friend class DtoaHelper; 188 }; 189 190 DiyFp GetCachedPower(int e); 191 static DiyFp GetCachedPowerByIndex(std::size_t index); 192 void GrisuRound(uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance); 193 static int CountDecimalDigit32(uint32_t n); 194 static uint32_t PopDigit(int kappa, uint32_t &p1); 195 void DigitGen(const DiyFp &w, const DiyFp &mp, uint64_t delta); 196 void Grisu(double value); 197 198 private: 199 char *buffer_; 200 int length_ {}; 201 int point_ {}; 202 int k_ {}; 203 }; 204 } // namespace ark::es2panda::util 205 #endif // ES2PANDA_UTIL_INCLUDE_DTOA_HELPER_H