• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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