opt DoubleToString

issue:issue:#I9BP84

Signed-off-by: dov1s <maojunwei1@huawei.com>
Change-Id: I4701f0c0e2cca61b0ad143dbab1c630f8ee6c49f
This commit is contained in:
dov1s 2024-03-27 11:49:04 +08:00
parent 5d9d9e4477
commit 1fbd86c756
8 changed files with 573 additions and 45 deletions

View File

@ -552,6 +552,7 @@ ecma_source = [
"ecmascript/base/array_helper.cpp",
"ecmascript/base/atomic_helper.cpp",
"ecmascript/base/builtins_base.cpp",
"ecmascript/base/dtoa_helper.cpp",
"ecmascript/base/error_helper.cpp",
"ecmascript/base/fast_json_stringifier.cpp",
"ecmascript/base/json_helper.cpp",

View File

@ -0,0 +1,223 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/dtoa_helper.h"
#ifndef UINT64_C2
#define UINT64_C2(high32, low32) ((static_cast<uint64_t>(high32) << 32) | static_cast<uint64_t>(low32))
#endif
namespace panda::ecmascript::base::dtoa {
DtoaHelper::DiyFp DtoaHelper::GetCachedPowerByIndex(size_t index)
{
// 10^-348, 10^-340, ..., 10^340
static const uint64_t kCachedPowers_F[] = {
UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76),
UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea),
UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df),
UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f),
UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c),
UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5),
UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d),
UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637),
UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7),
UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5),
UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b),
UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996),
UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6),
UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8),
UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053),
UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd),
UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94),
UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b),
UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac),
UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3),
UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb),
UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c),
UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000),
UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984),
UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70),
UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245),
UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8),
UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a),
UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea),
UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85),
UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2),
UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3),
UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25),
UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece),
UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5),
UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a),
UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c),
UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a),
UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129),
UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429),
UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d),
UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841),
UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9),
UINT64_C2(0xaf87023b, 0x9bf0ee6b)
};
static const int16_t kCachedPowers_E[] = {
-1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980,
-954, -927, -901, -874, -847, -821, -794, -768, -741, -715,
-688, -661, -635, -608, -582, -555, -529, -502, -475, -449,
-422, -396, -369, -343, -316, -289, -263, -236, -210, -183,
-157, -130, -103, -77, -50, -24, 3, 30, 56, 83,
109, 136, 162, 189, 216, 242, 269, 295, 322, 348,
375, 402, 428, 455, 481, 508, 534, 561, 588, 614,
641, 667, 694, 720, 747, 774, 800, 827, 853, 880,
907, 933, 960, 986, 1013, 1039, 1066
};
return DtoaHelper::DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]);
}
void DtoaHelper::GrisuRound(char *buffer, int len, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance)
{
while (rest < distance && delta - rest >= tenKappa &&
(rest + tenKappa < distance || distance - rest > rest + tenKappa - distance)) {
buffer[len - 1]--;
rest += tenKappa;
}
}
int DtoaHelper::CountDecimalDigit32(uint32_t n)
{
if (n < TEN) {
return 1; // 1: means the decimal digit
} else if (n < TEN2POW) {
return 2; // 2: means the decimal digit
} else if (n < TEN3POW) {
return 3; // 3: means the decimal digit
} else if (n < TEN4POW) {
return 4; // 4: means the decimal digit
} else if (n < TEN5POW) {
return 5; // 5: means the decimal digit
} else if (n < TEN6POW) {
return 6; // 6: means the decimal digit
} else if (n < TEN7POW) {
return 7; // 7: means the decimal digit
} else if (n < TEN8POW) {
return 8; // 8: means the decimal digit
} else {
return 9; // 9: means the decimal digit
}
}
void DtoaHelper::DigitGen(const DiyFp &W, const DiyFp &Mp, uint64_t delta, char *buffer, int *len, int *K)
{
const DiyFp one(uint64_t(1) << -Mp.e, Mp.e);
const DiyFp distance = Mp - W;
uint32_t p1 = static_cast<uint32_t>(Mp.f >> -one.e);
uint64_t p2 = Mp.f & (one.f - 1);
int kappa = CountDecimalDigit32(p1); // kappa in [0, 9]
*len = 0;
while (kappa > 0) {
uint32_t d = 0;
switch (kappa) {
case 9: // 9: means the decimal digit
d = p1 / TEN8POW;
p1 %= TEN8POW;
break;
case 8: // 8: means the decimal digit
d = p1 / TEN7POW;
p1 %= TEN7POW;
break;
case 7: // 7: means the decimal digit
d = p1 / TEN6POW;
p1 %= TEN6POW;
break;
case 6: // 6: means the decimal digit
d = p1 / TEN5POW;
p1 %= TEN5POW;
break;
case 5: // 5: means the decimal digit
d = p1 / TEN4POW;
p1 %= TEN4POW;
break;
case 4: // 4: means the decimal digit
d = p1 / TEN3POW;
p1 %= TEN3POW;
break;
case 3: // 3: means the decimal digit
d = p1 / TEN2POW;
p1 %= TEN2POW;
break;
case 2: // 2: means the decimal digit
d = p1 / TEN;
p1 %= TEN;
break;
case 1: // 1: means the decimal digit
d = p1;
p1 = 0;
break;
default:;
}
if (d || *len) {
buffer[(*len)++] = static_cast<char>('0' + static_cast<char>(d));
}
kappa--;
uint64_t tmp = (static_cast<uint64_t>(p1) << -one.e) + p2;
if (tmp <= delta) {
*K += kappa;
GrisuRound(buffer, *len, delta, tmp, POW10[kappa] << -one.e, distance.f);
return;
}
}
// kappa = 0
for (;;) {
p2 *= TEN;
delta *= TEN;
char d = static_cast<char>(p2 >> -one.e);
if (d || *len) {
buffer[(*len)++] = static_cast<char>('0' + d);
}
p2 &= one.f - 1;
kappa--;
if (p2 < delta) {
*K += kappa;
int index = -kappa;
GrisuRound(buffer, *len, delta, p2, one.f, distance.f * (index < kIndex ? POW10[index] : 0));
return;
}
}
}
// Grisu2 algorithm use the extra capacity of the used integer type to shorten the produced output
void DtoaHelper::Grisu(double value, char *buffer, int *length, int *K)
{
const DiyFp v(value);
DiyFp mMinus;
DiyFp mPlus;
v.NormalizedBoundaries(&mMinus, &mPlus);
const DiyFp cached = GetCachedPower(mPlus.e, K);
const DiyFp W = v.Normalize() * cached;
DiyFp wPlus = mPlus * cached;
DiyFp wMinus = mMinus * cached;
wMinus.f++;
wPlus.f--;
DigitGen(W, wPlus, wPlus.f - wMinus.f, buffer, length, K);
}
void DtoaHelper::Dtoa(double value, char *buffer, int *point, int *length)
{
// Exceptional case such as NAN, 0.0, negative... are processed in DoubleToEcmaString
// So use Dtoa should avoid Exceptional case.
ASSERT(value > 0);
int k;
Grisu(value, buffer, length, &k);
*point = *length + k;
}
}

View File

@ -0,0 +1,167 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef ECMASCRIPT_BASE_DTOA_HELPER_H
#define ECMASCRIPT_BASE_DTOA_HELPER_H
#include <math.h>
#include <stdint.h>
#include <stdint.h>
#include <limits>
#include "ecmascript/common.h"
namespace panda::ecmascript::base::dtoa {
class DtoaHelper {
public:
static constexpr int CACHED_POWERS_OFFSET = 348;
static constexpr double kD_1_LOG2_10 = 0.30102999566398114; //1 / lg(10)
static constexpr int kQ = -61;
static constexpr int kIndex = 20;
static constexpr int MIN_DECIMAL_EXPONENT = -348;
static constexpr uint64_t POW10[] = { 1ULL, 10ULL, 100ULL, 1000ULL, 10000ULL, 100000ULL, 1000000ULL,
10000000ULL, 100000000ULL, 1000000000ULL, 10000000000ULL, 100000000000ULL,
1000000000000ULL, 10000000000000ULL, 100000000000000ULL, 1000000000000000ULL,
10000000000000000ULL, 100000000000000000ULL, 1000000000000000000ULL,
10000000000000000000ULL };
static constexpr uint32_t TEN = 10;
static constexpr uint32_t TEN2POW = 100;
static constexpr uint32_t TEN3POW = 1000;
static constexpr uint32_t TEN4POW = 10000;
static constexpr uint32_t TEN5POW = 100000;
static constexpr uint32_t TEN6POW = 1000000;
static constexpr uint32_t TEN7POW = 10000000;
static constexpr uint32_t TEN8POW = 100000000;
// DiyFp is a floating-point number type, consists of a uint64 significand and one integer exponent.
struct DiyFp {
DiyFp() : f(), e() {}
DiyFp(uint64_t fp, int exp) : f(fp), e(exp) {}
explicit DiyFp(double d)
{
union {
double d;
uint64_t u64;
} u = { d };
int biased_e = static_cast<int>((u.u64 & kDpExponentMask) >> kDpSignificandSize);
uint64_t significand = (u.u64 & kDpSignificandMask);
if (biased_e != 0) {
f = significand + kDpHiddenBit;
e = biased_e - kDpExponentBias;
} else {
f = significand;
e = kDpMinExponent + 1;
}
}
DiyFp operator - (const DiyFp &rhs) const
{
return DiyFp(f - rhs.f, e);
}
DiyFp operator*(const DiyFp &rhs) const
{
const uint64_t M32 = 0xFFFFFFFF;
const uint64_t a = f >> 32;
const uint64_t b = f & M32;
const uint64_t c = rhs.f >> 32;
const uint64_t d = rhs.f & M32;
const uint64_t ac = a * c;
const uint64_t bc = b * c;
const uint64_t ad = a * d;
const uint64_t bd = b * d;
uint64_t tmp = (bd >> kInt32Bits) + (ad & M32) + (bc & M32);
tmp += 1U << kRoundBits; // mult_round
return DiyFp(ac + (ad >> kInt32Bits) + (bc >> kInt32Bits) + (tmp >> kInt32Bits), e + rhs.e + kInt64Bits);
}
DiyFp Normalize() const
{
DiyFp res = *this;
while (!(res.f & kDpHiddenBit)) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 1);
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1);
return res;
}
DiyFp NormalizeBoundary() const
{
DiyFp res = *this;
while (!(res.f & (kDpHiddenBit << 1))) {
res.f <<= 1;
res.e--;
}
res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter
res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); // 2: parameter
return res;
}
void NormalizedBoundaries(DiyFp *minus, DiyFp *plus) const
{
DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary();
DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) : DiyFp((f << 1) - 1, e - 1); // 2: parameter
mi.f <<= mi.e - pl.e;
mi.e = pl.e;
*plus = pl;
*minus = mi;
}
static const int kInt64Bits = 64;
static const int kInt32Bits = 32;
static const int kRoundBits = 31;
static const int kDiySignificandSize = 64;
static const int kDpSignificandSize = 52;
static const int kDpExponentBias = 0x3FF + kDpSignificandSize;
static const int kDpMaxExponent = 0x7FF - kDpExponentBias;
static const int kDpMinExponent = -kDpExponentBias;
static const int kDpDenormalExponent = -kDpExponentBias + 1;
static const uint64_t kDpExponentMask =
(static_cast<uint64_t>(0x7FF00000) << 32) | static_cast<uint64_t>(0x00000000);
static const uint64_t kDpSignificandMask =
(static_cast<uint64_t>(0x000FFFFF) << 32) | static_cast<uint64_t>(0xFFFFFFFF);
static const uint64_t kDpHiddenBit =
(static_cast<uint64_t>(0x00100000) << 32) | static_cast<uint64_t>(0x00000000);
uint64_t f;
int e;
};
static DiyFp GetCachedPower(int e, int *K)
{
// dk must be positive, so can do ceiling in positive
double dk = (kQ - e) * kD_1_LOG2_10 + CACHED_POWERS_OFFSET - 1;
int k = static_cast<int>(dk);
if (dk - k > 0.0) {
k++;
}
unsigned index = static_cast<unsigned>((k >> 3) + 1); // 3: parameter
*K = -(MIN_DECIMAL_EXPONENT + static_cast<int>(index << 3)); // 3: parameter
return GetCachedPowerByIndex(index);
}
static DiyFp GetCachedPowerByIndex(size_t index);
static void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, uint64_t tenKappa, uint64_t distance);
static int CountDecimalDigit32(uint32_t n);
static void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, char* buffer, int* len, int* K);
static void Grisu(double value, char* buffer, int* length, int* K);
static void Dtoa(double value, char* buffer, int* point, int* length);
};
}
#endif

View File

@ -24,6 +24,7 @@
#include <sys/time.h>
#include "ecmascript/base/builtins_base.h"
#include "ecmascript/base/dtoa_helper.h"
#include "ecmascript/base/string_helper.h"
#include "ecmascript/builtins/builtins_number.h"
#include "ecmascript/ecma_string_table.h"
@ -633,61 +634,28 @@ JSHandle<EcmaString> NumberHelper::DoubleToEcmaString(const JSThread *thread, do
}
ASSERT(d > 0);
// 5. Otherwise, let n, k, and s be integers such that k ≥ 1, 10k1 ≤ s < 10k, the Number value for s × 10nk is m,
// and k is as small as possible. If there are multiple possibilities for s, choose the value of s for which s ×
// 10nk is closest in value to m. If there are two such possible values of s, choose the one that is even. Note
// that k is the number of digits in the decimal representation of s and that s is not divisible by 10.
if (0.1 <= d && d < 1) { // 0.1: 10 ** -1
// Fast path. In this case, n==0, just need to calculate k and s.
std::string resultFast = "0.";
int64_t sFast = 0;
int kFast = 1;
int64_t power = 1;
while (kFast <= DOUBLE_MAX_PRECISION) {
power *= 10; // 10: base 10
int digitFast = static_cast<int64_t>(d * power) % 10; // 10: base 10
ASSERT(0 <= digitFast && digitFast <= 9); // 9: single digit max
sFast = sFast * 10 + digitFast; // 10: base 10
resultFast += (digitFast + '0');
if (sFast / static_cast<double>(power) == d) { // s * (10 ** -k)
result += resultFast;
return factory->NewFromASCII(result.c_str());
}
kFast++;
}
}
char buffer[JS_DTOA_BUF_SIZE] = {0};
int n = 0;
int k = GetMinmumDigits(d, &n, buffer);
int n; // decimal point
int k; // length
dtoa::DtoaHelper::Dtoa(d, buffer, &n, &k); //Fast Double To Ascii.
std::string base = buffer;
if (n > 0 && n <= MAX_DIGITS) {
base.erase(1, 1);
if (k <= n) {
// 6. If k ≤ n ≤ 21, return the String consisting of the code units of the k digits of the decimal
// representation of s (in order, with no leading zeroes), followed by nk occurrences of the code unit
// 0x0030 (DIGIT ZERO).
// 6. If k ≤ n ≤ 21
base += std::string(n - k, '0');
} else {
// 7. If 0 < n ≤ 21, return the String consisting of the code units of the most significant n digits of the
// decimal representation of s, followed by the code unit 0x002E (FULL STOP), followed by the code units of
// the remaining kn digits of the decimal representation of s.
// 7. If 0 < n ≤ 21
base.insert(n, 1, '.');
}
} else if (MIN_DIGITS < n && n <= 0) {
// 8. If 6 < n ≤ 0, return the String consisting of the code unit 0x0030 (DIGIT ZERO), followed by the code
// unit 0x002E (FULL STOP), followed by n occurrences of the code unit 0x0030 (DIGIT ZERO), followed by the
// code units of the k digits of the decimal representation of s.
base.erase(1, 1);
// 8. If 6 < n ≤ 0
base = std::string("0.") + std::string(-n, '0') + base;
} else {
if (k == 1) {
// 9. Otherwise, if k = 1, return the String consisting of the code unit of the single digit of s
base.erase(1, 1);
// 9. & 10. Otherwise
base.erase(1, k - 1);
if (k != 1) {
base += std::string(".") + std::string(buffer + 1);
}
// followed by code unit 0x0065 (LATIN SMALL LETTER E), followed by the code unit 0x002B (PLUS SIGN) or the
// code unit 0x002D (HYPHEN-MINUS) according to whether n1 is positive or negative, followed by the code
// units of the decimal representation of the integer abs(n1) (with no leading zeroes).
base += "e" + (n >= 1 ? std::string("+") : "") + std::to_string(n - 1);
}
result += base;

View File

@ -79,6 +79,7 @@ host_unittest_action("Base_003_Test") {
sources = [
# test file
"dtoa_helper_test.cpp",
"number_helper_test.cpp",
"string_helper_test.cpp",
"typed_array_helper_test.cpp",

View File

@ -0,0 +1,121 @@
/*
* Copyright (c) 2024 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "ecmascript/base/dtoa_helper.h"
#include "ecmascript/tests/test_helper.h"
using namespace panda::ecmascript;
using namespace panda::ecmascript::base;
using namespace panda::ecmascript::base::dtoa;
#define TEST_DTOA(d, str, buffer, n, k, e1, e2) \
DtoaHelper::Dtoa(d, buffer, &(n), &(k)); \
EXPECT_STREQ(str, buffer); \
EXPECT_EQ(n, e1); \
EXPECT_EQ(k, e2)
namespace panda::test {
class DtoaHelperTest : public testing::Test {
public:
static void SetUpTestCase()
{
GTEST_LOG_(INFO) << "SetUpTestCase";
}
static void TearDownTestCase()
{
GTEST_LOG_(INFO) << "TearDownCase";
}
void SetUp() override
{
TestHelper::CreateEcmaVMWithScope(instance, thread, scope);
}
void TearDown() override
{
TestHelper::DestroyEcmaVMWithScope(instance, scope);
}
EcmaVM *instance {nullptr};
EcmaHandleScope *scope {nullptr};
JSThread *thread {nullptr};
protected:
template <class To, class From>
inline To MemoryCast(const From &src) noexcept
{
static_assert(sizeof(To) == sizeof(From), "size of the types must be equal");
To dst;
if (memcpy_s(&dst, sizeof(To), &src, sizeof(From)) != EOK) {
LOG_FULL(FATAL) << "memcpy_s failed";
UNREACHABLE();
}
return dst;
}
};
HWTEST_F_L0(DtoaHelperTest, DoubleToAscii)
{
char buffer1[128];
int n1; //decimal_point
int k1; //length
TEST_DTOA(1.2345, "12345", buffer1, n1, k1, 1, 5);
char buffer2[128];
int n2;
int k2;
TEST_DTOA(1.2345678, "12345678", buffer2, n2, k2, 1, 8);
char buffer3[128];
int n3;
int k3;
TEST_DTOA(1e30, "1", buffer3, n3, k3, 31, 1);
char buffer4[128];
int n4;
int k4;
TEST_DTOA(79.39773355813419, "7939773355813419", buffer4, n4, k4, 2, 16);
char buffer5[128];
int n5;
int k5;
TEST_DTOA(0.0000001, "1", buffer5, n5, k5, -6, 1);
char buffer6[128];
int n6;
int k6;
TEST_DTOA(1.234567890123456e30, "1234567890123456", buffer6, n6, k6, 31, 16);
char buffer7[128];
int n7;
int k7;
TEST_DTOA(2.225073858507201e-308, "2225073858507201", buffer7, n7, k7, -307, 16); // Max subnormal positive double
char buffer8[128];
int n8;
int k8;
TEST_DTOA(2.2250738585072014e-308, "22250738585072014", buffer8, n8, k8, -307, 17); // Min normal positive double
char buffer9[128];
int n9;
int k9;
TEST_DTOA(1.7976931348623157e308, "17976931348623157", buffer9, n9, k9, 309, 17); // Max double
char buffera[128];
int na;
int ka;
TEST_DTOA(5e-301, "5", buffera, na, ka, -300, 1);
}
} // namespace panda::test

View File

@ -157,6 +157,53 @@ HWTEST_F_L0(NumberHelperTest, DoubleToString_002)
EXPECT_EQ(EcmaStringAccessor::Compare(instance, handleEcmaStr6, resultStr), 0);
}
/**
* @tc.name: DoubleToEcmaString
* @tc.desc: This function Convert the double type data into a EcmaString.
* @tc.type: FUNC
* @tc.require:
*/
HWTEST_F_L0(NumberHelperTest, DoubleToEcmaString)
{
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
JSHandle<EcmaString> resultStr1 =
factory->NewFromASCII("5562684646268003");
double d1 = 5562684646268003;
JSHandle<EcmaString> resultJSHandle1 = NumberHelper::DoubleToEcmaString(thread, d1);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle1, resultStr1), 0);
JSHandle<EcmaString> resultStr2 =
factory->NewFromASCII("0.005431");
double d2 = 0.005431;
JSHandle<EcmaString> resultJSHandle2 = NumberHelper::DoubleToEcmaString(thread, d2);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle2, resultStr2), 0);
JSHandle<EcmaString> resultStr3 =
factory->NewFromASCII("1.9045e-7");
double d3 = 0.00000019045;
JSHandle<EcmaString> resultJSHandle3 = NumberHelper::DoubleToEcmaString(thread, d3);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle3, resultStr3), 0);
JSHandle<EcmaString> resultStr4 =
factory->NewFromASCII("-79.39773355813419");
double d4 = -79.39773355813419;
JSHandle<EcmaString> resultJSHandle4 = NumberHelper::DoubleToEcmaString(thread, d4);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle4, resultStr4), 0);
JSHandle<EcmaString> resultStr5 =
factory->NewFromASCII("1e+21");
double d5 = 1e21;
JSHandle<EcmaString> resultJSHandle5 = NumberHelper::DoubleToEcmaString(thread, d5);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle5, resultStr5), 0);
JSHandle<EcmaString> resultStr6 =
factory->NewFromASCII("340000000000000000");
double d6 = 340000000000000000;
JSHandle<EcmaString> resultJSHandle6 = NumberHelper::DoubleToEcmaString(thread, d6);
EXPECT_EQ(EcmaStringAccessor::Compare(instance, resultJSHandle6, resultStr6), 0);
}
/**
* @tc.name: IsEmptyString
* @tc.desc: Check whether the character is empty string through "IsEmptyString" function.

View File

@ -39,8 +39,8 @@ let res:number = 1;
print(Math.cbrt()); //: NaN
// Check with single param
print(Math.cbrt(-0.027)); //: -0.29999999999999992
print(Math.cbrt(0.125)); //: 0.49999999999999992
print(Math.cbrt(-0.027)); //: -0.29999999999999993
print(Math.cbrt(0.125)); //: 0.49999999999999994
print(Math.cbrt(1)); //: 1
print(Math.cbrt(8)); //: 2
print(Math.cbrt(2146689000)); //: 1290.0000000000002