14514f5e3Sopenharmony_ci/* 24514f5e3Sopenharmony_ci * Copyright (c) 2022 Huawei Device Co., Ltd. 34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License. 54514f5e3Sopenharmony_ci * You may obtain a copy of the License at 64514f5e3Sopenharmony_ci * 74514f5e3Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 84514f5e3Sopenharmony_ci * 94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and 134514f5e3Sopenharmony_ci * limitations under the License. 144514f5e3Sopenharmony_ci */ 154514f5e3Sopenharmony_ci 164514f5e3Sopenharmony_ci#include "ecmascript/js_bigint.h" 174514f5e3Sopenharmony_ci 184514f5e3Sopenharmony_ci#include "ecmascript/global_env_constants-inl.h" 194514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_value-inl.h" 204514f5e3Sopenharmony_ci#include "ecmascript/js_tagged_number.h" 214514f5e3Sopenharmony_ci 224514f5e3Sopenharmony_cinamespace panda::ecmascript { 234514f5e3Sopenharmony_ciclass ObjectFactory; 244514f5e3Sopenharmony_ciconstexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz"; 254514f5e3Sopenharmony_cistatic int CharToInt(char c) 264514f5e3Sopenharmony_ci{ 274514f5e3Sopenharmony_ci uint32_t res = 0; 284514f5e3Sopenharmony_ci if (c >= '0' && c <= '9') { 294514f5e3Sopenharmony_ci res = c - '0'; 304514f5e3Sopenharmony_ci } else if (c >= 'A' && c <= 'Z') { 314514f5e3Sopenharmony_ci res = c - 'A' + 10; // 10:res must Greater than 10. 324514f5e3Sopenharmony_ci } else if (c >= 'a' && c <= 'z') { 334514f5e3Sopenharmony_ci res = c - 'a' + 10; // 10:res must Greater than 10 344514f5e3Sopenharmony_ci } 354514f5e3Sopenharmony_ci return static_cast<int>(res); 364514f5e3Sopenharmony_ci} 374514f5e3Sopenharmony_ci 384514f5e3Sopenharmony_cistatic void Division(CString &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain) 394514f5e3Sopenharmony_ci{ 404514f5e3Sopenharmony_ci ASSERT(conversionToRadix != 0); 414514f5e3Sopenharmony_ci uint32_t temp = 0; 424514f5e3Sopenharmony_ci remain = 0; 434514f5e3Sopenharmony_ci for (size_t i = 0; i < num.size(); i++) { 444514f5e3Sopenharmony_ci temp = (currentRadix * remain + static_cast<uint32_t>(CharToInt(num[i]))); 454514f5e3Sopenharmony_ci num[i] = dp[temp / conversionToRadix]; 464514f5e3Sopenharmony_ci remain = temp % conversionToRadix; 474514f5e3Sopenharmony_ci } 484514f5e3Sopenharmony_ci size_t count = 0; 494514f5e3Sopenharmony_ci while (count < num.size() && num[count] == '0') { 504514f5e3Sopenharmony_ci count++; 514514f5e3Sopenharmony_ci } 524514f5e3Sopenharmony_ci num = num.substr(count); 534514f5e3Sopenharmony_ci} 544514f5e3Sopenharmony_ci 554514f5e3Sopenharmony_ciCString BigIntHelper::Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix) 564514f5e3Sopenharmony_ci{ 574514f5e3Sopenharmony_ci ASSERT(conversionToRadix != 0); 584514f5e3Sopenharmony_ci CString newNum = num; 594514f5e3Sopenharmony_ci CString res; 604514f5e3Sopenharmony_ci uint32_t remain = 0; 614514f5e3Sopenharmony_ci while (newNum.size() != 0) { 624514f5e3Sopenharmony_ci Division(newNum, conversionToRadix, currentRadix, remain); 634514f5e3Sopenharmony_ci res = dp[remain] + res; 644514f5e3Sopenharmony_ci } 654514f5e3Sopenharmony_ci return res; 664514f5e3Sopenharmony_ci} 674514f5e3Sopenharmony_ci 684514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::CreateUint64MaxBigInt(JSThread *thread) 694514f5e3Sopenharmony_ci{ 704514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, 3); // 3:The number of digits in an object of type BigInt 714514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 724514f5e3Sopenharmony_ci bigint->SetDigit(0, 0); 734514f5e3Sopenharmony_ci bigint->SetDigit(1, 0); 744514f5e3Sopenharmony_ci bigint->SetDigit(2, 1); // 2:The number of digits in an object of type BigInt 754514f5e3Sopenharmony_ci return bigint; 764514f5e3Sopenharmony_ci} 774514f5e3Sopenharmony_ci 784514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::CreateInt64MaxBigInt(JSThread *thread) 794514f5e3Sopenharmony_ci{ 804514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, 2); // 2:The number of digits in an object of type BigInt 814514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 824514f5e3Sopenharmony_ci bigint->SetDigit(0, 0); 834514f5e3Sopenharmony_ci bigint->SetDigit(1, 0x80000000); // 0x80000000:Int MAX 844514f5e3Sopenharmony_ci return bigint; 854514f5e3Sopenharmony_ci} 864514f5e3Sopenharmony_ci 874514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::GetUint64MaxBigInt(JSThread *thread) 884514f5e3Sopenharmony_ci{ 894514f5e3Sopenharmony_ci return JSHandle<BigInt>::Cast(thread->GlobalConstants()->GetHandledUint64MaxBigInt()); 904514f5e3Sopenharmony_ci} 914514f5e3Sopenharmony_ci 924514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::GetInt64MaxBigInt(JSThread *thread) 934514f5e3Sopenharmony_ci{ 944514f5e3Sopenharmony_ci return JSHandle<BigInt>::Cast(thread->GlobalConstants()->GetHandledInt64MaxBigInt()); 954514f5e3Sopenharmony_ci} 964514f5e3Sopenharmony_ci 974514f5e3Sopenharmony_ciJSHandle<BigInt> BigIntHelper::SetBigInt(JSThread *thread, const CString &numStr, uint32_t currentRadix) 984514f5e3Sopenharmony_ci{ 994514f5e3Sopenharmony_ci int flag = 0; 1004514f5e3Sopenharmony_ci if (numStr[0] == '-') { 1014514f5e3Sopenharmony_ci flag = 1; 1024514f5e3Sopenharmony_ci } 1034514f5e3Sopenharmony_ci 1044514f5e3Sopenharmony_ci CString binaryStr = ""; 1054514f5e3Sopenharmony_ci if (currentRadix != BigInt::BINARY) { 1064514f5e3Sopenharmony_ci binaryStr = Conversion(numStr.substr(flag), BigInt::BINARY, currentRadix); 1074514f5e3Sopenharmony_ci } else { 1084514f5e3Sopenharmony_ci binaryStr = numStr.substr(flag); 1094514f5e3Sopenharmony_ci } 1104514f5e3Sopenharmony_ci 1114514f5e3Sopenharmony_ci JSHandle<BigInt> bigint; 1124514f5e3Sopenharmony_ci size_t binaryStrLen = binaryStr.size(); 1134514f5e3Sopenharmony_ci size_t len = binaryStrLen / BigInt::DATEBITS; 1144514f5e3Sopenharmony_ci size_t mod = binaryStrLen % BigInt::DATEBITS; 1154514f5e3Sopenharmony_ci int index = 0; 1164514f5e3Sopenharmony_ci if (mod == 0) { 1174514f5e3Sopenharmony_ci index = static_cast<int>(len - 1); 1184514f5e3Sopenharmony_ci bigint = BigInt::CreateBigint(thread, len); 1194514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 1204514f5e3Sopenharmony_ci } else { 1214514f5e3Sopenharmony_ci len++; 1224514f5e3Sopenharmony_ci index = static_cast<int>(len - 1); 1234514f5e3Sopenharmony_ci bigint = BigInt::CreateBigint(thread, len); 1244514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 1254514f5e3Sopenharmony_ci uint32_t val = 0; 1264514f5e3Sopenharmony_ci for (size_t i = 0; i < mod; ++i) { 1274514f5e3Sopenharmony_ci val <<= 1; 1284514f5e3Sopenharmony_ci val |= static_cast<uint32_t>(binaryStr[i] - '0'); 1294514f5e3Sopenharmony_ci } 1304514f5e3Sopenharmony_ci bigint->SetDigit(index, val); 1314514f5e3Sopenharmony_ci index--; 1324514f5e3Sopenharmony_ci } 1334514f5e3Sopenharmony_ci if (flag == 1) { 1344514f5e3Sopenharmony_ci bigint->SetSign(true); 1354514f5e3Sopenharmony_ci } 1364514f5e3Sopenharmony_ci size_t i = mod; 1374514f5e3Sopenharmony_ci while (i < binaryStrLen) { 1384514f5e3Sopenharmony_ci uint32_t val = 0; 1394514f5e3Sopenharmony_ci for (size_t j = 0; j < BigInt::DATEBITS && i < binaryStrLen; ++j, ++i) { 1404514f5e3Sopenharmony_ci val <<= 1; 1414514f5e3Sopenharmony_ci val |= static_cast<uint32_t>(binaryStr[i] - '0'); 1424514f5e3Sopenharmony_ci } 1434514f5e3Sopenharmony_ci bigint->SetDigit(index, val); 1444514f5e3Sopenharmony_ci index--; 1454514f5e3Sopenharmony_ci } 1464514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 1474514f5e3Sopenharmony_ci} 1484514f5e3Sopenharmony_ci 1494514f5e3Sopenharmony_ciJSHandle<BigInt> BigIntHelper::RightTruncate(JSThread *thread, JSHandle<BigInt> x) 1504514f5e3Sopenharmony_ci{ 1514514f5e3Sopenharmony_ci int len = static_cast<int>(x->GetLength()); 1524514f5e3Sopenharmony_ci ASSERT(len != 0); 1534514f5e3Sopenharmony_ci if (len == 1 && x->GetDigit(0) == 0) { 1544514f5e3Sopenharmony_ci x->SetSign(false); 1554514f5e3Sopenharmony_ci return x; 1564514f5e3Sopenharmony_ci } 1574514f5e3Sopenharmony_ci int index = len - 1; 1584514f5e3Sopenharmony_ci if (x->GetDigit(index) != 0) { 1594514f5e3Sopenharmony_ci return x; 1604514f5e3Sopenharmony_ci } 1614514f5e3Sopenharmony_ci while (index >= 0) { 1624514f5e3Sopenharmony_ci if (x->GetDigit(index) != 0) { 1634514f5e3Sopenharmony_ci break; 1644514f5e3Sopenharmony_ci } 1654514f5e3Sopenharmony_ci index--; 1664514f5e3Sopenharmony_ci } 1674514f5e3Sopenharmony_ci 1684514f5e3Sopenharmony_ci if (index == -1) { 1694514f5e3Sopenharmony_ci return BigInt::Int32ToBigInt(thread, 0); 1704514f5e3Sopenharmony_ci } else { 1714514f5e3Sopenharmony_ci ASSERT(index >= 0); 1724514f5e3Sopenharmony_ci return BigInt::Copy(thread, x, index + 1); 1734514f5e3Sopenharmony_ci } 1744514f5e3Sopenharmony_ci} 1754514f5e3Sopenharmony_ci 1764514f5e3Sopenharmony_ciCString BigIntHelper::GetBinary(const BigInt *bigint) 1774514f5e3Sopenharmony_ci{ 1784514f5e3Sopenharmony_ci ASSERT(bigint != nullptr); 1794514f5e3Sopenharmony_ci int index = 0; 1804514f5e3Sopenharmony_ci int len = static_cast<int>(bigint->GetLength()); 1814514f5e3Sopenharmony_ci int strLen = BigInt::DATEBITS * len; 1824514f5e3Sopenharmony_ci CString res(strLen, '0'); 1834514f5e3Sopenharmony_ci int strIndex = strLen - 1; 1844514f5e3Sopenharmony_ci while (index < len) { 1854514f5e3Sopenharmony_ci int bityLen = BigInt::DATEBITS; 1864514f5e3Sopenharmony_ci uint32_t val = bigint->GetDigit(index); 1874514f5e3Sopenharmony_ci while (bityLen--) { 1884514f5e3Sopenharmony_ci res[strIndex--] = (val & 1) + '0'; 1894514f5e3Sopenharmony_ci val = val >> 1; 1904514f5e3Sopenharmony_ci } 1914514f5e3Sopenharmony_ci index++; 1924514f5e3Sopenharmony_ci } 1934514f5e3Sopenharmony_ci DeZero(res); 1944514f5e3Sopenharmony_ci return res; 1954514f5e3Sopenharmony_ci} 1964514f5e3Sopenharmony_ci 1974514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::CreateBigint(JSThread *thread, uint32_t length) 1984514f5e3Sopenharmony_ci{ 1994514f5e3Sopenharmony_ci if (length > MAXSIZE) { 2004514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 2014514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Maximum BigInt size exceeded", bigint); 2024514f5e3Sopenharmony_ci } 2034514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 2044514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = factory->NewBigInt(length); 2054514f5e3Sopenharmony_ci return bigint; 2064514f5e3Sopenharmony_ci} 2074514f5e3Sopenharmony_ci 2084514f5e3Sopenharmony_ci// 6.1.6.2.13 2094514f5e3Sopenharmony_cibool BigInt::Equal(const JSTaggedValue &x, const JSTaggedValue &y) 2104514f5e3Sopenharmony_ci{ 2114514f5e3Sopenharmony_ci BigInt* xVal = BigInt::Cast(x.GetTaggedObject()); 2124514f5e3Sopenharmony_ci BigInt* yVal = BigInt::Cast(y.GetTaggedObject()); 2134514f5e3Sopenharmony_ci return Equal(xVal, yVal); 2144514f5e3Sopenharmony_ci} 2154514f5e3Sopenharmony_ci 2164514f5e3Sopenharmony_cibool BigInt::Equal(const BigInt *x, const BigInt *y) 2174514f5e3Sopenharmony_ci{ 2184514f5e3Sopenharmony_ci ASSERT(x != nullptr); 2194514f5e3Sopenharmony_ci ASSERT(y != nullptr); 2204514f5e3Sopenharmony_ci if (x->GetSign() != y->GetSign() || x->GetLength() != y->GetLength()) { 2214514f5e3Sopenharmony_ci return false; 2224514f5e3Sopenharmony_ci } 2234514f5e3Sopenharmony_ci for (uint32_t i = 0; i < x->GetLength(); ++i) { 2244514f5e3Sopenharmony_ci if (x->GetDigit(i) != y->GetDigit(i)) { 2254514f5e3Sopenharmony_ci return false; 2264514f5e3Sopenharmony_ci } 2274514f5e3Sopenharmony_ci } 2284514f5e3Sopenharmony_ci return true; 2294514f5e3Sopenharmony_ci} 2304514f5e3Sopenharmony_ci 2314514f5e3Sopenharmony_ci// 6.1.6.2.14 2324514f5e3Sopenharmony_cibool BigInt::SameValue(const JSTaggedValue &x, const JSTaggedValue &y) 2334514f5e3Sopenharmony_ci{ 2344514f5e3Sopenharmony_ci return Equal(x, y); 2354514f5e3Sopenharmony_ci} 2364514f5e3Sopenharmony_ci 2374514f5e3Sopenharmony_ci// 6.1.6.2.15 2384514f5e3Sopenharmony_cibool BigInt::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y) 2394514f5e3Sopenharmony_ci{ 2404514f5e3Sopenharmony_ci return Equal(x, y); 2414514f5e3Sopenharmony_ci} 2424514f5e3Sopenharmony_ci 2434514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y) 2444514f5e3Sopenharmony_ci{ 2454514f5e3Sopenharmony_ci uint32_t maxLen = 0; 2464514f5e3Sopenharmony_ci uint32_t minLen = 0; 2474514f5e3Sopenharmony_ci uint32_t xlen = x->GetLength(); 2484514f5e3Sopenharmony_ci uint32_t ylen = y->GetLength(); 2494514f5e3Sopenharmony_ci if (xlen > ylen) { 2504514f5e3Sopenharmony_ci maxLen = xlen; 2514514f5e3Sopenharmony_ci minLen = ylen; 2524514f5e3Sopenharmony_ci } else { 2534514f5e3Sopenharmony_ci maxLen = ylen; 2544514f5e3Sopenharmony_ci minLen = xlen; 2554514f5e3Sopenharmony_ci } 2564514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, maxLen); 2574514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 2584514f5e3Sopenharmony_ci for (size_t i = 0; i < minLen; ++i) { 2594514f5e3Sopenharmony_ci if (op == Operate::OR) { 2604514f5e3Sopenharmony_ci bigint->SetDigit(i, x->GetDigit(i) | y->GetDigit(i)); 2614514f5e3Sopenharmony_ci } else if (op == Operate::AND) { 2624514f5e3Sopenharmony_ci bigint->SetDigit(i, x->GetDigit(i) & y->GetDigit(i)); 2634514f5e3Sopenharmony_ci } else { 2644514f5e3Sopenharmony_ci ASSERT(op == Operate::XOR); 2654514f5e3Sopenharmony_ci bigint->SetDigit(i, x->GetDigit(i) ^ y->GetDigit(i)); 2664514f5e3Sopenharmony_ci } 2674514f5e3Sopenharmony_ci } 2684514f5e3Sopenharmony_ci if (op == Operate::OR || op == Operate::XOR) { 2694514f5e3Sopenharmony_ci if (xlen > ylen) { 2704514f5e3Sopenharmony_ci for (size_t i = ylen; i < xlen; ++i) { 2714514f5e3Sopenharmony_ci bigint->SetDigit(i, x->GetDigit(i)); 2724514f5e3Sopenharmony_ci } 2734514f5e3Sopenharmony_ci } else if (ylen > xlen) { 2744514f5e3Sopenharmony_ci for (size_t i = xlen; i < ylen; ++i) { 2754514f5e3Sopenharmony_ci bigint->SetDigit(i, y->GetDigit(i)); 2764514f5e3Sopenharmony_ci } 2774514f5e3Sopenharmony_ci } 2784514f5e3Sopenharmony_ci } 2794514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 2804514f5e3Sopenharmony_ci} 2814514f5e3Sopenharmony_ci 2824514f5e3Sopenharmony_ciJSHandle<BigInt> OneIsNegativeAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 2834514f5e3Sopenharmony_ci{ 2844514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength()); 2854514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 2864514f5e3Sopenharmony_ci uint32_t xLength = x->GetLength(); 2874514f5e3Sopenharmony_ci uint32_t yLength = yVal->GetLength(); 2884514f5e3Sopenharmony_ci uint32_t minLen = xLength; 2894514f5e3Sopenharmony_ci if (xLength > yLength) { 2904514f5e3Sopenharmony_ci minLen = yLength; 2914514f5e3Sopenharmony_ci } 2924514f5e3Sopenharmony_ci JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, xLength); 2934514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 2944514f5e3Sopenharmony_ci uint32_t i = 0; 2954514f5e3Sopenharmony_ci while (i < minLen) { 2964514f5e3Sopenharmony_ci uint32_t res = x->GetDigit(i) & ~(yVal->GetDigit(i)); 2974514f5e3Sopenharmony_ci newBigint->SetDigit(i, res); 2984514f5e3Sopenharmony_ci ++i; 2994514f5e3Sopenharmony_ci } 3004514f5e3Sopenharmony_ci while (i < xLength) { 3014514f5e3Sopenharmony_ci newBigint->SetDigit(i, x->GetDigit(i)); 3024514f5e3Sopenharmony_ci ++i; 3034514f5e3Sopenharmony_ci } 3044514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, newBigint); 3054514f5e3Sopenharmony_ci} 3064514f5e3Sopenharmony_ci 3074514f5e3Sopenharmony_ci// 6.1.6.2.20 BigInt::bitwiseAND ( x, y ) 3084514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 3094514f5e3Sopenharmony_ci{ 3104514f5e3Sopenharmony_ci if (x->GetSign() && y->GetSign()) { 3114514f5e3Sopenharmony_ci // (-x) & (-y) == -(((x-1) | (y-1)) + 1) 3124514f5e3Sopenharmony_ci JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength()); 3134514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3144514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength()); 3154514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3164514f5e3Sopenharmony_ci JSHandle<BigInt> temp = BitwiseOp(thread, Operate::OR, xVal, yVal); 3174514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3184514f5e3Sopenharmony_ci JSHandle<BigInt> res = BitwiseAddOne(thread, temp); 3194514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3204514f5e3Sopenharmony_ci return res; 3214514f5e3Sopenharmony_ci } 3224514f5e3Sopenharmony_ci if (x->GetSign() != y->GetSign()) { 3234514f5e3Sopenharmony_ci // x & (-y) == x & ~(y-1) 3244514f5e3Sopenharmony_ci if (!x->GetSign()) { 3254514f5e3Sopenharmony_ci return OneIsNegativeAND(thread, x, y); 3264514f5e3Sopenharmony_ci } else { 3274514f5e3Sopenharmony_ci return OneIsNegativeAND(thread, y, x); 3284514f5e3Sopenharmony_ci } 3294514f5e3Sopenharmony_ci } 3304514f5e3Sopenharmony_ci return BitwiseOp(thread, Operate::AND, x, y); 3314514f5e3Sopenharmony_ci} 3324514f5e3Sopenharmony_ci 3334514f5e3Sopenharmony_ciJSHandle<BigInt> OneIsNegativeXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 3344514f5e3Sopenharmony_ci{ 3354514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength()); 3364514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3374514f5e3Sopenharmony_ci JSHandle<BigInt> temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal); 3384514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3394514f5e3Sopenharmony_ci JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp); 3404514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3414514f5e3Sopenharmony_ci return res; 3424514f5e3Sopenharmony_ci} 3434514f5e3Sopenharmony_ci 3444514f5e3Sopenharmony_ci// 6.1.6.2.21 BigInt::bitwiseOR ( x, y ) 3454514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 3464514f5e3Sopenharmony_ci{ 3474514f5e3Sopenharmony_ci if (x->GetSign() && y->GetSign()) { 3484514f5e3Sopenharmony_ci // (-x) ^ (-y) == (x-1) ^ (y-1) 3494514f5e3Sopenharmony_ci JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength()); 3504514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3514514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength()); 3524514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3534514f5e3Sopenharmony_ci return BitwiseOp(thread, Operate::XOR, xVal, yVal); 3544514f5e3Sopenharmony_ci } 3554514f5e3Sopenharmony_ci if (x->GetSign() != y->GetSign()) { 3564514f5e3Sopenharmony_ci // x ^ (-y) == -((x ^ (y-1)) + 1) 3574514f5e3Sopenharmony_ci if (!x->GetSign()) { 3584514f5e3Sopenharmony_ci return OneIsNegativeXOR(thread, x, y); 3594514f5e3Sopenharmony_ci } else { 3604514f5e3Sopenharmony_ci return OneIsNegativeXOR(thread, y, x); 3614514f5e3Sopenharmony_ci } 3624514f5e3Sopenharmony_ci } 3634514f5e3Sopenharmony_ci return BitwiseOp(thread, Operate::XOR, x, y); 3644514f5e3Sopenharmony_ci} 3654514f5e3Sopenharmony_ci 3664514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen) 3674514f5e3Sopenharmony_ci{ 3684514f5e3Sopenharmony_ci ASSERT(!bigint->IsZero()); 3694514f5e3Sopenharmony_ci ASSERT(maxLen >= bigint->GetLength()); 3704514f5e3Sopenharmony_ci 3714514f5e3Sopenharmony_ci JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, maxLen); 3724514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 3734514f5e3Sopenharmony_ci uint32_t bigintLen = bigint->GetLength(); 3744514f5e3Sopenharmony_ci uint32_t carry = 1; 3754514f5e3Sopenharmony_ci for (uint32_t i = 0; i < bigintLen; i++) { 3764514f5e3Sopenharmony_ci uint32_t bigintCarry = 0; 3774514f5e3Sopenharmony_ci newBigint->SetDigit(i, BigIntHelper::SubHelper(bigint->GetDigit(i), carry, bigintCarry)); 3784514f5e3Sopenharmony_ci carry = bigintCarry; 3794514f5e3Sopenharmony_ci } 3804514f5e3Sopenharmony_ci ASSERT(!carry); 3814514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, newBigint); 3824514f5e3Sopenharmony_ci} 3834514f5e3Sopenharmony_ci 3844514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint) 3854514f5e3Sopenharmony_ci{ 3864514f5e3Sopenharmony_ci uint32_t bigintLength = bigint->GetLength(); 3874514f5e3Sopenharmony_ci 3884514f5e3Sopenharmony_ci bool needExpend = true; 3894514f5e3Sopenharmony_ci for (uint32_t i = 0; i < bigintLength; i++) { 3904514f5e3Sopenharmony_ci if (std::numeric_limits<uint32_t>::max() != bigint->GetDigit(i)) { 3914514f5e3Sopenharmony_ci needExpend = false; 3924514f5e3Sopenharmony_ci break; 3934514f5e3Sopenharmony_ci } 3944514f5e3Sopenharmony_ci } 3954514f5e3Sopenharmony_ci uint32_t newLength = bigintLength; 3964514f5e3Sopenharmony_ci if (needExpend) { 3974514f5e3Sopenharmony_ci newLength += 1; 3984514f5e3Sopenharmony_ci } 3994514f5e3Sopenharmony_ci JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, newLength); 4004514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4014514f5e3Sopenharmony_ci uint32_t carry = 1; 4024514f5e3Sopenharmony_ci for (uint32_t i = 0; i < bigintLength; i++) { 4034514f5e3Sopenharmony_ci uint32_t bigintCarry = 0; 4044514f5e3Sopenharmony_ci newBigint->SetDigit(i, BigIntHelper::AddHelper(bigint->GetDigit(i), carry, bigintCarry)); 4054514f5e3Sopenharmony_ci carry = bigintCarry; 4064514f5e3Sopenharmony_ci } 4074514f5e3Sopenharmony_ci if (needExpend) { 4084514f5e3Sopenharmony_ci newBigint->SetDigit(bigintLength, carry); 4094514f5e3Sopenharmony_ci } 4104514f5e3Sopenharmony_ci newBigint->SetSign(true); 4114514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, newBigint); 4124514f5e3Sopenharmony_ci} 4134514f5e3Sopenharmony_ci 4144514f5e3Sopenharmony_ciJSHandle<BigInt> OneIsNegativeOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 4154514f5e3Sopenharmony_ci{ 4164514f5e3Sopenharmony_ci uint32_t xLength = x->GetLength(); 4174514f5e3Sopenharmony_ci uint32_t maxLen = xLength; 4184514f5e3Sopenharmony_ci if (maxLen < y->GetLength()) { 4194514f5e3Sopenharmony_ci maxLen = y->GetLength(); 4204514f5e3Sopenharmony_ci } 4214514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, maxLen); 4224514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4234514f5e3Sopenharmony_ci uint32_t yLength = yVal->GetLength(); 4244514f5e3Sopenharmony_ci uint32_t minLen = xLength; 4254514f5e3Sopenharmony_ci if (minLen > yLength) { 4264514f5e3Sopenharmony_ci minLen = yLength; 4274514f5e3Sopenharmony_ci } 4284514f5e3Sopenharmony_ci JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, yLength); 4294514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4304514f5e3Sopenharmony_ci uint32_t i = 0; 4314514f5e3Sopenharmony_ci while (i < minLen) { 4324514f5e3Sopenharmony_ci uint32_t res = ~(x->GetDigit(i)) & yVal->GetDigit(i); 4334514f5e3Sopenharmony_ci newBigint->SetDigit(i, res); 4344514f5e3Sopenharmony_ci ++i; 4354514f5e3Sopenharmony_ci } 4364514f5e3Sopenharmony_ci while (i < yLength) { 4374514f5e3Sopenharmony_ci newBigint->SetDigit(i, yVal->GetDigit(i)); 4384514f5e3Sopenharmony_ci ++i; 4394514f5e3Sopenharmony_ci } 4404514f5e3Sopenharmony_ci JSHandle<BigInt> temp = BigIntHelper::RightTruncate(thread, newBigint); 4414514f5e3Sopenharmony_ci JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp); 4424514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4434514f5e3Sopenharmony_ci res->SetSign(true); 4444514f5e3Sopenharmony_ci return res; 4454514f5e3Sopenharmony_ci} 4464514f5e3Sopenharmony_ci 4474514f5e3Sopenharmony_ci// 6.1.6.2.22 BigInt::bitwiseOR ( x, y ) 4484514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 4494514f5e3Sopenharmony_ci{ 4504514f5e3Sopenharmony_ci if (x->GetSign() && y->GetSign()) { 4514514f5e3Sopenharmony_ci // (-x) | (-y) == -(((x-1) & (y-1)) + 1) 4524514f5e3Sopenharmony_ci uint32_t maxLen = x->GetLength(); 4534514f5e3Sopenharmony_ci uint32_t yLen = y->GetLength(); 4544514f5e3Sopenharmony_ci maxLen < yLen ? maxLen = yLen : 0; 4554514f5e3Sopenharmony_ci JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, maxLen); 4564514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4574514f5e3Sopenharmony_ci JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, yLen); 4584514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4594514f5e3Sopenharmony_ci JSHandle<BigInt> temp = BitwiseOp(thread, Operate::AND, xVal, yVal); 4604514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4614514f5e3Sopenharmony_ci JSHandle<BigInt> res = BitwiseAddOne(thread, temp); 4624514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 4634514f5e3Sopenharmony_ci res->SetSign(true); 4644514f5e3Sopenharmony_ci return res; 4654514f5e3Sopenharmony_ci } 4664514f5e3Sopenharmony_ci if (x->GetSign() != y->GetSign()) { 4674514f5e3Sopenharmony_ci // x | (-y) == -(((y-1) & ~x) + 1) 4684514f5e3Sopenharmony_ci if (!x->GetSign()) { 4694514f5e3Sopenharmony_ci return OneIsNegativeOR(thread, x, y); 4704514f5e3Sopenharmony_ci } else { 4714514f5e3Sopenharmony_ci return OneIsNegativeOR(thread, y, x); 4724514f5e3Sopenharmony_ci } 4734514f5e3Sopenharmony_ci } 4744514f5e3Sopenharmony_ci return BitwiseOp(thread, Operate::OR, x, y); 4754514f5e3Sopenharmony_ci} 4764514f5e3Sopenharmony_ci 4774514f5e3Sopenharmony_ci// 6.1.6.2.23 BigInt::toString ( x ) 4784514f5e3Sopenharmony_ciJSHandle<EcmaString> BigInt::ToString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix) 4794514f5e3Sopenharmony_ci{ 4804514f5e3Sopenharmony_ci ObjectFactory *factory = thread->GetEcmaVM()->GetFactory(); 4814514f5e3Sopenharmony_ci CString result = bigint->ToStdString(conversionToRadix); 4824514f5e3Sopenharmony_ci return factory->NewFromASCII(result.c_str()); 4834514f5e3Sopenharmony_ci} 4844514f5e3Sopenharmony_ci 4854514f5e3Sopenharmony_ciCString BigInt::ToStdString(uint32_t conversionToRadix) const 4864514f5e3Sopenharmony_ci{ 4874514f5e3Sopenharmony_ci CString result = 4884514f5e3Sopenharmony_ci BigIntHelper::Conversion(BigIntHelper::GetBinary(this), conversionToRadix, BINARY); 4894514f5e3Sopenharmony_ci if (GetSign()) { 4904514f5e3Sopenharmony_ci result = "-" + result; 4914514f5e3Sopenharmony_ci } 4924514f5e3Sopenharmony_ci return result; 4934514f5e3Sopenharmony_ci} 4944514f5e3Sopenharmony_ci 4954514f5e3Sopenharmony_ciJSTaggedValue BigInt::NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number) 4964514f5e3Sopenharmony_ci{ 4974514f5e3Sopenharmony_ci if (!number->IsInteger()) { 4984514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "The number cannot be converted to a BigInt because it is not an integer", 4994514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 5004514f5e3Sopenharmony_ci } 5014514f5e3Sopenharmony_ci double num = number->GetNumber(); 5024514f5e3Sopenharmony_ci if (num == 0.0) { 5034514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0).GetTaggedValue(); 5044514f5e3Sopenharmony_ci } 5054514f5e3Sopenharmony_ci return DoubleToBigInt(thread, num); 5064514f5e3Sopenharmony_ci} 5074514f5e3Sopenharmony_ci 5084514f5e3Sopenharmony_ciJSTaggedValue BigInt::DoubleToBigInt(JSThread *thread, double num) 5094514f5e3Sopenharmony_ci{ 5104514f5e3Sopenharmony_ci // Bit operations must be of integer type 5114514f5e3Sopenharmony_ci uint64_t bits = 0; 5124514f5e3Sopenharmony_ci if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) { 5134514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "memcpy_s failed"; 5144514f5e3Sopenharmony_ci UNREACHABLE(); 5154514f5e3Sopenharmony_ci } 5164514f5e3Sopenharmony_ci // Take out bits 62-52 (11 bits in total) and subtract 1023 5174514f5e3Sopenharmony_ci uint64_t integerDigits = ((bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF) - base::DOUBLE_EXPONENT_BIAS; 5184514f5e3Sopenharmony_ci uint32_t mayNeedLen = integerDigits / DATEBITS + 1; 5194514f5e3Sopenharmony_ci 5204514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, mayNeedLen); 5214514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 5224514f5e3Sopenharmony_ci bigint->SetSign(num < 0); 5234514f5e3Sopenharmony_ci uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT; 5244514f5e3Sopenharmony_ci int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; 5254514f5e3Sopenharmony_ci 5264514f5e3Sopenharmony_ci int leftover = 0; 5274514f5e3Sopenharmony_ci bool isFirstInto = true; 5284514f5e3Sopenharmony_ci for (int index = static_cast<int>(mayNeedLen - 1); index >= 0; --index) { 5294514f5e3Sopenharmony_ci uint32_t doubleNum = 0; 5304514f5e3Sopenharmony_ci if (isFirstInto) { 5314514f5e3Sopenharmony_ci isFirstInto = false; 5324514f5e3Sopenharmony_ci leftover = mantissaSize - static_cast<int>(integerDigits % DATEBITS); 5334514f5e3Sopenharmony_ci doubleNum = static_cast<uint32_t>(mantissa >> leftover); 5344514f5e3Sopenharmony_ci mantissa = mantissa << (64 - leftover); // 64 : double bits size 5354514f5e3Sopenharmony_ci bigint->SetDigit(index, doubleNum); 5364514f5e3Sopenharmony_ci } else { 5374514f5e3Sopenharmony_ci leftover -= DATEBITS; 5384514f5e3Sopenharmony_ci doubleNum = static_cast<uint32_t>(mantissa >> DATEBITS); 5394514f5e3Sopenharmony_ci mantissa = mantissa << DATEBITS; 5404514f5e3Sopenharmony_ci bigint->SetDigit(index, doubleNum); 5414514f5e3Sopenharmony_ci } 5424514f5e3Sopenharmony_ci } 5434514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint).GetTaggedValue(); 5444514f5e3Sopenharmony_ci} 5454514f5e3Sopenharmony_ci 5464514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Int32ToBigInt(JSThread *thread, const int &number) 5474514f5e3Sopenharmony_ci{ 5484514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, 1); 5494514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 5504514f5e3Sopenharmony_ci uint32_t value = 0; 5514514f5e3Sopenharmony_ci bool sign = number < 0; 5524514f5e3Sopenharmony_ci if (sign) { 5534514f5e3Sopenharmony_ci value = static_cast<uint32_t>(-(number + 1)) + 1; 5544514f5e3Sopenharmony_ci } else { 5554514f5e3Sopenharmony_ci value = number; 5564514f5e3Sopenharmony_ci } 5574514f5e3Sopenharmony_ci bigint->SetDigit(0, value); 5584514f5e3Sopenharmony_ci bigint->SetSign(sign); 5594514f5e3Sopenharmony_ci return bigint; 5604514f5e3Sopenharmony_ci} 5614514f5e3Sopenharmony_ci 5624514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Uint32ToBigInt(JSThread *thread, const uint32_t &number) 5634514f5e3Sopenharmony_ci{ 5644514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, 1); 5654514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 5664514f5e3Sopenharmony_ci bigint->SetDigit(0, number); 5674514f5e3Sopenharmony_ci return bigint; 5684514f5e3Sopenharmony_ci} 5694514f5e3Sopenharmony_ci 5704514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number) 5714514f5e3Sopenharmony_ci{ 5724514f5e3Sopenharmony_ci uint64_t value = 0; 5734514f5e3Sopenharmony_ci bool sign = number < 0; 5744514f5e3Sopenharmony_ci if (sign) { 5754514f5e3Sopenharmony_ci value = static_cast<uint64_t>(-(number + 1)) + 1; 5764514f5e3Sopenharmony_ci } else { 5774514f5e3Sopenharmony_ci value = number; 5784514f5e3Sopenharmony_ci } 5794514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = Uint64ToBigInt(thread, value); 5804514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 5814514f5e3Sopenharmony_ci bigint->SetSign(sign); 5824514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 5834514f5e3Sopenharmony_ci} 5844514f5e3Sopenharmony_ci 5854514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number) 5864514f5e3Sopenharmony_ci{ 5874514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, 2); // 2 : one int64_t bits need two uint32_t bits 5884514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 5894514f5e3Sopenharmony_ci uint32_t lowBits = static_cast<uint32_t>(number & 0xffffffff); 5904514f5e3Sopenharmony_ci uint32_t highBits = static_cast<uint32_t>((number >> DATEBITS) & 0xffffffff); 5914514f5e3Sopenharmony_ci bigint->SetDigit(0, lowBits); 5924514f5e3Sopenharmony_ci bigint->SetDigit(1, highBits); 5934514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 5944514f5e3Sopenharmony_ci} 5954514f5e3Sopenharmony_ci 5964514f5e3Sopenharmony_ciuint64_t BigInt::ToUint64() 5974514f5e3Sopenharmony_ci{ 5984514f5e3Sopenharmony_ci uint32_t len = GetLength(); 5994514f5e3Sopenharmony_ci ASSERT(len <= 2); // The maximum length of the BigInt data is less or equal 2 6004514f5e3Sopenharmony_ci uint32_t lowBits = GetDigit(0); 6014514f5e3Sopenharmony_ci uint32_t highBits = 0; 6024514f5e3Sopenharmony_ci if (len > 1) { 6034514f5e3Sopenharmony_ci highBits = GetDigit(1); 6044514f5e3Sopenharmony_ci } 6054514f5e3Sopenharmony_ci uint64_t value = static_cast<uint64_t>(lowBits); 6064514f5e3Sopenharmony_ci value |= static_cast<uint64_t>(highBits) << DATEBITS; 6074514f5e3Sopenharmony_ci if (GetSign()) { 6084514f5e3Sopenharmony_ci value = ~(value - 1); 6094514f5e3Sopenharmony_ci } 6104514f5e3Sopenharmony_ci return value; 6114514f5e3Sopenharmony_ci} 6124514f5e3Sopenharmony_ci 6134514f5e3Sopenharmony_ciint64_t BigInt::ToInt64() 6144514f5e3Sopenharmony_ci{ 6154514f5e3Sopenharmony_ci return static_cast<int64_t>(ToUint64()); 6164514f5e3Sopenharmony_ci} 6174514f5e3Sopenharmony_ci 6184514f5e3Sopenharmony_civoid BigInt::BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless) 6194514f5e3Sopenharmony_ci{ 6204514f5e3Sopenharmony_ci ASSERT(cValue != nullptr); 6214514f5e3Sopenharmony_ci ASSERT(lossless != nullptr); 6224514f5e3Sopenharmony_ci if (bigint->IsBoolean()) { 6234514f5e3Sopenharmony_ci bigint = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, bigint)); 6244514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6254514f5e3Sopenharmony_ci } else if (!bigint->IsBigInt()) { 6264514f5e3Sopenharmony_ci JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint)); 6274514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6284514f5e3Sopenharmony_ci *cValue = bigInt64->ToInt64(); 6294514f5e3Sopenharmony_ci return; 6304514f5e3Sopenharmony_ci } 6314514f5e3Sopenharmony_ci JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint)); 6324514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6334514f5e3Sopenharmony_ci if (Equal(bigInt64.GetTaggedValue(), bigint.GetTaggedValue())) { 6344514f5e3Sopenharmony_ci *lossless = true; 6354514f5e3Sopenharmony_ci } else { 6364514f5e3Sopenharmony_ci *lossless = false; 6374514f5e3Sopenharmony_ci } 6384514f5e3Sopenharmony_ci *cValue = bigInt64->ToInt64(); 6394514f5e3Sopenharmony_ci} 6404514f5e3Sopenharmony_ci 6414514f5e3Sopenharmony_civoid BigInt::BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless) 6424514f5e3Sopenharmony_ci{ 6434514f5e3Sopenharmony_ci ASSERT(cValue != nullptr); 6444514f5e3Sopenharmony_ci ASSERT(lossless != nullptr); 6454514f5e3Sopenharmony_ci if (bigint->IsBoolean()) { 6464514f5e3Sopenharmony_ci bigint = JSHandle<JSTaggedValue>(thread, JSTaggedValue::ToBigInt(thread, bigint)); 6474514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6484514f5e3Sopenharmony_ci } else if (!bigint->IsBigInt()) { 6494514f5e3Sopenharmony_ci JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigUint64(thread, bigint)); 6504514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6514514f5e3Sopenharmony_ci *cValue = bigInt64->ToInt64(); 6524514f5e3Sopenharmony_ci return; 6534514f5e3Sopenharmony_ci } 6544514f5e3Sopenharmony_ci JSHandle<BigInt> bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigint)); 6554514f5e3Sopenharmony_ci RETURN_IF_ABRUPT_COMPLETION(thread); 6564514f5e3Sopenharmony_ci if (Equal(bigUint64.GetTaggedValue(), bigint.GetTaggedValue())) { 6574514f5e3Sopenharmony_ci *lossless = true; 6584514f5e3Sopenharmony_ci } else { 6594514f5e3Sopenharmony_ci *lossless = false; 6604514f5e3Sopenharmony_ci } 6614514f5e3Sopenharmony_ci *cValue = bigUint64->ToUint64(); 6624514f5e3Sopenharmony_ci} 6634514f5e3Sopenharmony_ci 6644514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t *words) 6654514f5e3Sopenharmony_ci{ 6664514f5e3Sopenharmony_ci ASSERT(words != nullptr); 6674514f5e3Sopenharmony_ci if (size == 0) { 6684514f5e3Sopenharmony_ci return Uint64ToBigInt(thread, 0); 6694514f5e3Sopenharmony_ci } 6704514f5e3Sopenharmony_ci const uint32_t MULTIPLE = 2; 6714514f5e3Sopenharmony_ci uint32_t needLen = size * MULTIPLE; 6724514f5e3Sopenharmony_ci if (needLen > MAXSIZE) { 6734514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 6744514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Maximum BigInt size exceeded", bigint); 6754514f5e3Sopenharmony_ci } 6764514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, needLen); 6774514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 6784514f5e3Sopenharmony_ci for (uint32_t index = 0; index < size; ++index) { 6794514f5e3Sopenharmony_ci uint32_t lowBits = static_cast<uint32_t>(words[index] & 0xffffffff); 6804514f5e3Sopenharmony_ci uint32_t highBits = static_cast<uint32_t>((words[index] >> DATEBITS) & 0xffffffff); 6814514f5e3Sopenharmony_ci bigint->SetDigit(MULTIPLE * index, lowBits); 6824514f5e3Sopenharmony_ci bigint->SetDigit(MULTIPLE * index + 1, highBits); 6834514f5e3Sopenharmony_ci } 6844514f5e3Sopenharmony_ci bigint->SetSign(sign); 6854514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 6864514f5e3Sopenharmony_ci} 6874514f5e3Sopenharmony_ci 6884514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 6894514f5e3Sopenharmony_ci{ 6904514f5e3Sopenharmony_ci bool xSignFlag = x->GetSign(); 6914514f5e3Sopenharmony_ci bool ySignFlag = y->GetSign(); 6924514f5e3Sopenharmony_ci // x + y == x + y 6934514f5e3Sopenharmony_ci // -x + -y == -(x + y) 6944514f5e3Sopenharmony_ci if (xSignFlag == ySignFlag) { 6954514f5e3Sopenharmony_ci return BigintAdd(thread, x, y, xSignFlag); 6964514f5e3Sopenharmony_ci } 6974514f5e3Sopenharmony_ci // x + -y == x - y == -(y - x) 6984514f5e3Sopenharmony_ci // -x + y == y - x == -(x - y) 6994514f5e3Sopenharmony_ci uint32_t xLength = x->GetLength(); 7004514f5e3Sopenharmony_ci uint32_t yLength = y->GetLength(); 7014514f5e3Sopenharmony_ci int i = static_cast<int>(xLength) - 1; 7024514f5e3Sopenharmony_ci int subSize = static_cast<int>(xLength - yLength); 7034514f5e3Sopenharmony_ci if (subSize > 0) { 7044514f5e3Sopenharmony_ci return BigintSub(thread, x, y, xSignFlag); 7054514f5e3Sopenharmony_ci } else if (subSize == 0) { 7064514f5e3Sopenharmony_ci while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) { 7074514f5e3Sopenharmony_ci i--; 7084514f5e3Sopenharmony_ci } 7094514f5e3Sopenharmony_ci if ((x->GetDigit(i) > y->GetDigit(i))) { 7104514f5e3Sopenharmony_ci return BigintSub(thread, x, y, xSignFlag); 7114514f5e3Sopenharmony_ci } else { 7124514f5e3Sopenharmony_ci return BigintSub(thread, y, x, ySignFlag); 7134514f5e3Sopenharmony_ci } 7144514f5e3Sopenharmony_ci } else { 7154514f5e3Sopenharmony_ci return BigintSub(thread, y, x, ySignFlag); 7164514f5e3Sopenharmony_ci } 7174514f5e3Sopenharmony_ci} 7184514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 7194514f5e3Sopenharmony_ci{ 7204514f5e3Sopenharmony_ci bool xSignFlag = x->GetSign(); 7214514f5e3Sopenharmony_ci bool ySignFlag = y->GetSign(); 7224514f5e3Sopenharmony_ci if (xSignFlag != ySignFlag) { 7234514f5e3Sopenharmony_ci // x - (-y) == x + y 7244514f5e3Sopenharmony_ci // (-x) - y == -(x + y) 7254514f5e3Sopenharmony_ci return BigintAdd(thread, x, y, xSignFlag); 7264514f5e3Sopenharmony_ci } 7274514f5e3Sopenharmony_ci // x - y == -(y - x) 7284514f5e3Sopenharmony_ci // (-x) - (-y) == y - x == -(x - y) 7294514f5e3Sopenharmony_ci uint32_t xLength = x->GetLength(); 7304514f5e3Sopenharmony_ci uint32_t yLength = y->GetLength(); 7314514f5e3Sopenharmony_ci ASSERT(xLength > 0); 7324514f5e3Sopenharmony_ci uint32_t i = xLength - 1; 7334514f5e3Sopenharmony_ci int subSize = static_cast<int>(xLength - yLength); 7344514f5e3Sopenharmony_ci if (subSize > 0) { 7354514f5e3Sopenharmony_ci return BigintSub(thread, x, y, xSignFlag); 7364514f5e3Sopenharmony_ci } else if (subSize == 0) { 7374514f5e3Sopenharmony_ci while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) { 7384514f5e3Sopenharmony_ci i--; 7394514f5e3Sopenharmony_ci } 7404514f5e3Sopenharmony_ci if ((x->GetDigit(i) > y->GetDigit(i))) { 7414514f5e3Sopenharmony_ci return BigintSub(thread, x, y, xSignFlag); 7424514f5e3Sopenharmony_ci } else { 7434514f5e3Sopenharmony_ci return BigintSub(thread, y, x, !ySignFlag); 7444514f5e3Sopenharmony_ci } 7454514f5e3Sopenharmony_ci } else { 7464514f5e3Sopenharmony_ci return BigintSub(thread, y, x, !ySignFlag); 7474514f5e3Sopenharmony_ci } 7484514f5e3Sopenharmony_ci} 7494514f5e3Sopenharmony_ci 7504514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign) 7514514f5e3Sopenharmony_ci{ 7524514f5e3Sopenharmony_ci if (x->GetLength() < y->GetLength()) { 7534514f5e3Sopenharmony_ci return BigintAdd(thread, y, x, resultSign); 7544514f5e3Sopenharmony_ci } 7554514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength() + 1); 7564514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 7574514f5e3Sopenharmony_ci uint32_t bigintCarry = 0; 7584514f5e3Sopenharmony_ci uint32_t i = 0; 7594514f5e3Sopenharmony_ci while (i < y->GetLength()) { 7604514f5e3Sopenharmony_ci uint32_t newBigintCarry = 0; 7614514f5e3Sopenharmony_ci uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry); 7624514f5e3Sopenharmony_ci addPlus = BigIntHelper::AddHelper(addPlus, bigintCarry, newBigintCarry); 7634514f5e3Sopenharmony_ci bigint->SetDigit(i, addPlus); 7644514f5e3Sopenharmony_ci bigintCarry = newBigintCarry; 7654514f5e3Sopenharmony_ci i++; 7664514f5e3Sopenharmony_ci } 7674514f5e3Sopenharmony_ci while (i < x->GetLength()) { 7684514f5e3Sopenharmony_ci uint32_t newBigintCarry = 0; 7694514f5e3Sopenharmony_ci uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigintCarry, newBigintCarry); 7704514f5e3Sopenharmony_ci bigint->SetDigit(i, addPlus); 7714514f5e3Sopenharmony_ci bigintCarry = newBigintCarry; 7724514f5e3Sopenharmony_ci i++; 7734514f5e3Sopenharmony_ci } 7744514f5e3Sopenharmony_ci bigint->SetDigit(i, bigintCarry); 7754514f5e3Sopenharmony_ci bigint->SetSign(resultSign); 7764514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 7774514f5e3Sopenharmony_ci} 7784514f5e3Sopenharmony_ci 7794514f5e3Sopenharmony_ciinline uint32_t BigIntHelper::AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry) 7804514f5e3Sopenharmony_ci{ 7814514f5e3Sopenharmony_ci uint32_t addPlus = x + y; 7824514f5e3Sopenharmony_ci if (addPlus < x) { 7834514f5e3Sopenharmony_ci bigintCarry += 1; 7844514f5e3Sopenharmony_ci } 7854514f5e3Sopenharmony_ci return addPlus; 7864514f5e3Sopenharmony_ci} 7874514f5e3Sopenharmony_ci 7884514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign) 7894514f5e3Sopenharmony_ci{ 7904514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength()); 7914514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 7924514f5e3Sopenharmony_ci uint32_t bigintCarry = 0; 7934514f5e3Sopenharmony_ci uint32_t i = 0; 7944514f5e3Sopenharmony_ci while (i < y->GetLength()) { 7954514f5e3Sopenharmony_ci uint32_t newBigintCarry = 0; 7964514f5e3Sopenharmony_ci uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry); 7974514f5e3Sopenharmony_ci minuSub = BigIntHelper::SubHelper(minuSub, bigintCarry, newBigintCarry); 7984514f5e3Sopenharmony_ci bigint->SetDigit(i, minuSub); 7994514f5e3Sopenharmony_ci bigintCarry = newBigintCarry; 8004514f5e3Sopenharmony_ci i++; 8014514f5e3Sopenharmony_ci } 8024514f5e3Sopenharmony_ci while (i < x->GetLength()) { 8034514f5e3Sopenharmony_ci uint32_t newBigintCarry = 0; 8044514f5e3Sopenharmony_ci uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigintCarry, newBigintCarry); 8054514f5e3Sopenharmony_ci bigint->SetDigit(i, minuSub); 8064514f5e3Sopenharmony_ci bigintCarry = newBigintCarry; 8074514f5e3Sopenharmony_ci i++; 8084514f5e3Sopenharmony_ci } 8094514f5e3Sopenharmony_ci bigint->SetSign(resultSign); 8104514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 8114514f5e3Sopenharmony_ci} 8124514f5e3Sopenharmony_ci 8134514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BigintAddOne(JSThread *thread, JSHandle<BigInt> x) 8144514f5e3Sopenharmony_ci{ 8154514f5e3Sopenharmony_ci JSHandle<BigInt> temp = Int32ToBigInt(thread, 1); 8164514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 8174514f5e3Sopenharmony_ci return Add(thread, x, temp); 8184514f5e3Sopenharmony_ci} 8194514f5e3Sopenharmony_ci 8204514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BigintSubOne(JSThread *thread, JSHandle<BigInt> x) 8214514f5e3Sopenharmony_ci{ 8224514f5e3Sopenharmony_ci JSHandle<BigInt> temp = Int32ToBigInt(thread, 1); 8234514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 8244514f5e3Sopenharmony_ci return Subtract(thread, x, temp); 8254514f5e3Sopenharmony_ci} 8264514f5e3Sopenharmony_ci 8274514f5e3Sopenharmony_ciinline uint32_t BigIntHelper::SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry) 8284514f5e3Sopenharmony_ci{ 8294514f5e3Sopenharmony_ci ASSERT(x - y >= 0); 8304514f5e3Sopenharmony_ci uint32_t minuSub = x - y; 8314514f5e3Sopenharmony_ci if (minuSub > x) { 8324514f5e3Sopenharmony_ci bigintCarry += 1; 8334514f5e3Sopenharmony_ci } 8344514f5e3Sopenharmony_ci return minuSub; 8354514f5e3Sopenharmony_ci} 8364514f5e3Sopenharmony_ci 8374514f5e3Sopenharmony_ciComparisonResult BigInt::Compare(const JSTaggedValue &x, const JSTaggedValue &y) 8384514f5e3Sopenharmony_ci{ 8394514f5e3Sopenharmony_ci BigInt* xVal = BigInt::Cast(x.GetTaggedObject()); 8404514f5e3Sopenharmony_ci BigInt* yVal = BigInt::Cast(y.GetTaggedObject()); 8414514f5e3Sopenharmony_ci return Compare(xVal, yVal); 8424514f5e3Sopenharmony_ci} 8434514f5e3Sopenharmony_ci 8444514f5e3Sopenharmony_ciComparisonResult BigInt::Compare(const BigInt *x, const BigInt *y) 8454514f5e3Sopenharmony_ci{ 8464514f5e3Sopenharmony_ci bool xSign = x->GetSign(); 8474514f5e3Sopenharmony_ci bool ySign = y->GetSign(); 8484514f5e3Sopenharmony_ci if (xSign != ySign) { 8494514f5e3Sopenharmony_ci return xSign ? ComparisonResult::LESS : ComparisonResult::GREAT; 8504514f5e3Sopenharmony_ci } 8514514f5e3Sopenharmony_ci ComparisonResult compar = AbsolutelyCompare(x, y); 8524514f5e3Sopenharmony_ci if (xSign && compar != ComparisonResult::EQUAL) { 8534514f5e3Sopenharmony_ci return compar == ComparisonResult::LESS ? ComparisonResult::GREAT : ComparisonResult::LESS; 8544514f5e3Sopenharmony_ci } 8554514f5e3Sopenharmony_ci return compar; 8564514f5e3Sopenharmony_ci} 8574514f5e3Sopenharmony_ci 8584514f5e3Sopenharmony_cibool BigInt::LessThan(const JSTaggedValue &x, const JSTaggedValue &y) 8594514f5e3Sopenharmony_ci{ 8604514f5e3Sopenharmony_ci return Compare(x, y) == ComparisonResult::LESS; 8614514f5e3Sopenharmony_ci} 8624514f5e3Sopenharmony_ci 8634514f5e3Sopenharmony_cibool BigInt::LessThan(const BigInt *x, const BigInt *y) 8644514f5e3Sopenharmony_ci{ 8654514f5e3Sopenharmony_ci ASSERT(x != nullptr); 8664514f5e3Sopenharmony_ci ASSERT(y != nullptr); 8674514f5e3Sopenharmony_ci return Compare(x, y) == ComparisonResult::LESS; 8684514f5e3Sopenharmony_ci} 8694514f5e3Sopenharmony_ci 8704514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 8714514f5e3Sopenharmony_ci{ 8724514f5e3Sopenharmony_ci if (x->IsZero() || y->IsZero()) { 8734514f5e3Sopenharmony_ci return x; 8744514f5e3Sopenharmony_ci } 8754514f5e3Sopenharmony_ci if (y->GetSign()) { 8764514f5e3Sopenharmony_ci return LeftShiftHelper(thread, x, y); 8774514f5e3Sopenharmony_ci } else { 8784514f5e3Sopenharmony_ci return RightShiftHelper(thread, x, y); 8794514f5e3Sopenharmony_ci } 8804514f5e3Sopenharmony_ci} 8814514f5e3Sopenharmony_ci 8824514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::ReturnIfRightShiftOverMax(JSThread *thread, bool sign) 8834514f5e3Sopenharmony_ci{ 8844514f5e3Sopenharmony_ci if (sign) { 8854514f5e3Sopenharmony_ci return Int32ToBigInt(thread, -1); 8864514f5e3Sopenharmony_ci } 8874514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0); 8884514f5e3Sopenharmony_ci} 8894514f5e3Sopenharmony_ci 8904514f5e3Sopenharmony_civoid BigInt::RightShift(JSHandle<BigInt> bigint, JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove) 8914514f5e3Sopenharmony_ci{ 8924514f5e3Sopenharmony_ci uint32_t size = x->GetLength(); 8934514f5e3Sopenharmony_ci if (bitsMove == 0) { 8944514f5e3Sopenharmony_ci for (uint32_t i = digitMove; i < size; i++) { 8954514f5e3Sopenharmony_ci bigint->SetDigit(i - digitMove, x->GetDigit(i)); 8964514f5e3Sopenharmony_ci } 8974514f5e3Sopenharmony_ci } else { 8984514f5e3Sopenharmony_ci uint32_t carry = x->GetDigit(digitMove) >> bitsMove; 8994514f5e3Sopenharmony_ci ASSERT(size > digitMove); 9004514f5e3Sopenharmony_ci uint32_t last = size - digitMove - 1; 9014514f5e3Sopenharmony_ci for (uint32_t i = 0; i < last; i++) { 9024514f5e3Sopenharmony_ci uint32_t value = x->GetDigit(i + digitMove + 1); 9034514f5e3Sopenharmony_ci bigint->SetDigit(i, (value << (DATEBITS - bitsMove)) | carry); 9044514f5e3Sopenharmony_ci carry = value >> bitsMove; 9054514f5e3Sopenharmony_ci } 9064514f5e3Sopenharmony_ci bigint->SetDigit(last, carry); 9074514f5e3Sopenharmony_ci } 9084514f5e3Sopenharmony_ci} 9094514f5e3Sopenharmony_ci 9104514f5e3Sopenharmony_civoid BigInt::JudgeRoundDown(JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove, uint32_t &needLen, 9114514f5e3Sopenharmony_ci bool &roundDown) 9124514f5e3Sopenharmony_ci{ 9134514f5e3Sopenharmony_ci uint32_t stamp = (static_cast<uint32_t>(1U) << bitsMove) - 1; 9144514f5e3Sopenharmony_ci if (x->GetDigit(digitMove) & stamp) { 9154514f5e3Sopenharmony_ci roundDown = true; 9164514f5e3Sopenharmony_ci } else { 9174514f5e3Sopenharmony_ci for (uint32_t i = 0; i < digitMove; i++) { 9184514f5e3Sopenharmony_ci if (x->GetDigit(i) != 0) { 9194514f5e3Sopenharmony_ci roundDown = true; 9204514f5e3Sopenharmony_ci break; 9214514f5e3Sopenharmony_ci } 9224514f5e3Sopenharmony_ci } 9234514f5e3Sopenharmony_ci } 9244514f5e3Sopenharmony_ci 9254514f5e3Sopenharmony_ci if (roundDown && bitsMove == 0) { 9264514f5e3Sopenharmony_ci ASSERT(x->GetLength() > 0); 9274514f5e3Sopenharmony_ci uint32_t highBits = x->GetDigit(x->GetLength() - 1); 9284514f5e3Sopenharmony_ci // If all the most significant bits are 1, we think that carry will cause overflow, 9294514f5e3Sopenharmony_ci // and needLen needs to be increased by 1 9304514f5e3Sopenharmony_ci if ((~highBits) == 0) { 9314514f5e3Sopenharmony_ci needLen++; 9324514f5e3Sopenharmony_ci } 9334514f5e3Sopenharmony_ci } 9344514f5e3Sopenharmony_ci} 9354514f5e3Sopenharmony_ci 9364514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 9374514f5e3Sopenharmony_ci{ 9384514f5e3Sopenharmony_ci bool sign = x->GetSign(); 9394514f5e3Sopenharmony_ci if (y->GetLength() > 1 || y->GetDigit(0) > MAXBITS) { 9404514f5e3Sopenharmony_ci return ReturnIfRightShiftOverMax(thread, sign); 9414514f5e3Sopenharmony_ci } 9424514f5e3Sopenharmony_ci uint32_t moveNum = y->GetDigit(0); 9434514f5e3Sopenharmony_ci uint32_t digitMove = moveNum / DATEBITS; 9444514f5e3Sopenharmony_ci uint32_t bitsMove = moveNum % DATEBITS; 9454514f5e3Sopenharmony_ci if (x->GetLength() <= digitMove) { 9464514f5e3Sopenharmony_ci return ReturnIfRightShiftOverMax(thread, sign); 9474514f5e3Sopenharmony_ci } 9484514f5e3Sopenharmony_ci uint32_t needLen = x->GetLength() - digitMove; 9494514f5e3Sopenharmony_ci bool roundDown = false; 9504514f5e3Sopenharmony_ci if (sign) { 9514514f5e3Sopenharmony_ci // If it is a negative number, you need to consider whether it will carry after moving. 9524514f5e3Sopenharmony_ci // NeedLen may need to increase by 1 9534514f5e3Sopenharmony_ci JudgeRoundDown(x, digitMove, bitsMove, needLen, roundDown); 9544514f5e3Sopenharmony_ci } 9554514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, needLen); 9564514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 9574514f5e3Sopenharmony_ci 9584514f5e3Sopenharmony_ci RightShift(bigint, x, digitMove, bitsMove); 9594514f5e3Sopenharmony_ci bigint = BigIntHelper::RightTruncate(thread, bigint); 9604514f5e3Sopenharmony_ci if (sign) { 9614514f5e3Sopenharmony_ci bigint->SetSign(true); 9624514f5e3Sopenharmony_ci if (roundDown) { 9634514f5e3Sopenharmony_ci return BitwiseAddOne(thread, bigint); 9644514f5e3Sopenharmony_ci } 9654514f5e3Sopenharmony_ci } 9664514f5e3Sopenharmony_ci return bigint; 9674514f5e3Sopenharmony_ci} 9684514f5e3Sopenharmony_ci 9694514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 9704514f5e3Sopenharmony_ci{ 9714514f5e3Sopenharmony_ci if (y->GetSign()) { 9724514f5e3Sopenharmony_ci return RightShiftHelper(thread, x, y); 9734514f5e3Sopenharmony_ci } else { 9744514f5e3Sopenharmony_ci return LeftShiftHelper(thread, x, y); 9754514f5e3Sopenharmony_ci } 9764514f5e3Sopenharmony_ci} 9774514f5e3Sopenharmony_ci 9784514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 9794514f5e3Sopenharmony_ci{ 9804514f5e3Sopenharmony_ci if (x->IsZero()) { 9814514f5e3Sopenharmony_ci return x; 9824514f5e3Sopenharmony_ci } 9834514f5e3Sopenharmony_ci ASSERT(y->GetLength() > 0); 9844514f5e3Sopenharmony_ci uint32_t moveNum = y->GetDigit(0); 9854514f5e3Sopenharmony_ci uint32_t digitMove = moveNum / DATEBITS; 9864514f5e3Sopenharmony_ci uint32_t bitsMove = moveNum % DATEBITS; 9874514f5e3Sopenharmony_ci // If bitsMove is not zero, needLen needs to be increased by 1 9884514f5e3Sopenharmony_ci uint32_t needLen = digitMove + x->GetLength() + static_cast<uint32_t>(!!bitsMove); 9894514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, needLen); 9904514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 9914514f5e3Sopenharmony_ci if (bitsMove == 0) { 9924514f5e3Sopenharmony_ci uint32_t index = digitMove; 9934514f5e3Sopenharmony_ci while (index < needLen) { 9944514f5e3Sopenharmony_ci bigint->SetDigit(index, x->GetDigit(index - digitMove)); 9954514f5e3Sopenharmony_ci ++index; 9964514f5e3Sopenharmony_ci } 9974514f5e3Sopenharmony_ci } else { 9984514f5e3Sopenharmony_ci uint32_t carry = 0; 9994514f5e3Sopenharmony_ci uint32_t index = 0; 10004514f5e3Sopenharmony_ci while (index < x->GetLength()) { 10014514f5e3Sopenharmony_ci uint32_t value = x->GetDigit(index); 10024514f5e3Sopenharmony_ci bigint->SetDigit(index + digitMove, (value << bitsMove) | carry); 10034514f5e3Sopenharmony_ci carry = value >> (DATEBITS - bitsMove); 10044514f5e3Sopenharmony_ci ++index; 10054514f5e3Sopenharmony_ci } 10064514f5e3Sopenharmony_ci if (carry != 0) { 10074514f5e3Sopenharmony_ci ASSERT(index + digitMove < needLen); 10084514f5e3Sopenharmony_ci bigint->SetDigit(index + digitMove, carry); 10094514f5e3Sopenharmony_ci } 10104514f5e3Sopenharmony_ci } 10114514f5e3Sopenharmony_ci bigint->SetSign(x->GetSign()); 10124514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 10134514f5e3Sopenharmony_ci} 10144514f5e3Sopenharmony_ci 10154514f5e3Sopenharmony_ciJSTaggedValue BigInt::UnsignedRightShift(JSThread *thread) 10164514f5e3Sopenharmony_ci{ 10174514f5e3Sopenharmony_ci THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt have no unsigned right shift, use >> instead", 10184514f5e3Sopenharmony_ci JSTaggedValue::Exception()); 10194514f5e3Sopenharmony_ci} 10204514f5e3Sopenharmony_ci 10214514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Copy(JSThread *thread, JSHandle<BigInt> x, uint32_t len) 10224514f5e3Sopenharmony_ci{ 10234514f5e3Sopenharmony_ci ASSERT(x->GetLength() >= len); 10244514f5e3Sopenharmony_ci JSHandle<BigInt> newBig = CreateBigint(thread, len); 10254514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 10264514f5e3Sopenharmony_ci std::copy(x->GetData(), x->GetData() + len, newBig->GetData()); 10274514f5e3Sopenharmony_ci newBig->SetSign(x->GetSign()); 10284514f5e3Sopenharmony_ci return newBig; 10294514f5e3Sopenharmony_ci} 10304514f5e3Sopenharmony_ci 10314514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::UnaryMinus(JSThread *thread, JSHandle<BigInt> x) 10324514f5e3Sopenharmony_ci{ 10334514f5e3Sopenharmony_ci if (x->IsZero()) { 10344514f5e3Sopenharmony_ci return x; 10354514f5e3Sopenharmony_ci } 10364514f5e3Sopenharmony_ci JSHandle<BigInt> y = Copy(thread, x, x->GetLength()); 10374514f5e3Sopenharmony_ci y->SetSign(!y->GetSign()); 10384514f5e3Sopenharmony_ci return y; 10394514f5e3Sopenharmony_ci} 10404514f5e3Sopenharmony_ci 10414514f5e3Sopenharmony_ci// 6.1.6.2.2 BigInt::bitwiseNOT ( x ) 10424514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::BitwiseNOT(JSThread *thread, JSHandle<BigInt> x) 10434514f5e3Sopenharmony_ci{ 10444514f5e3Sopenharmony_ci // ~(-x) == ~(~(x-1)) == x-1 10454514f5e3Sopenharmony_ci // ~x == -x-1 == -(x+1) 10464514f5e3Sopenharmony_ci JSHandle<BigInt> result = BigintAddOne(thread, x); 10474514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 10484514f5e3Sopenharmony_ci if (x->GetSign()) { 10494514f5e3Sopenharmony_ci result->SetSign(false); 10504514f5e3Sopenharmony_ci } else { 10514514f5e3Sopenharmony_ci result->SetSign(true); 10524514f5e3Sopenharmony_ci } 10534514f5e3Sopenharmony_ci return result; 10544514f5e3Sopenharmony_ci} 10554514f5e3Sopenharmony_ci 10564514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent) 10574514f5e3Sopenharmony_ci{ 10584514f5e3Sopenharmony_ci if (exponent->GetSign()) { 10594514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 10604514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Exponent must be positive", bigint); 10614514f5e3Sopenharmony_ci } 10624514f5e3Sopenharmony_ci ASSERT(exponent->GetLength() > 0); 10634514f5e3Sopenharmony_ci if (exponent->IsZero()) { 10644514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 1); 10654514f5e3Sopenharmony_ci } 10664514f5e3Sopenharmony_ci if (base->IsZero()) { 10674514f5e3Sopenharmony_ci return base; 10684514f5e3Sopenharmony_ci } 10694514f5e3Sopenharmony_ci uint32_t expValue = exponent->GetDigit(0); 10704514f5e3Sopenharmony_ci if (base->GetLength() == 1 && base->GetDigit(0) == 1) { 10714514f5e3Sopenharmony_ci if (base->GetSign() && !(expValue & 1)) { 10724514f5e3Sopenharmony_ci return BigInt::UnaryMinus(thread, base); 10734514f5e3Sopenharmony_ci } 10744514f5e3Sopenharmony_ci return base; 10754514f5e3Sopenharmony_ci } 10764514f5e3Sopenharmony_ci if (exponent->GetLength() > 1) { 10774514f5e3Sopenharmony_ci // The result is at least 2n ** 2n ** 32n, which is too big. 10784514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 10794514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Maximum BigInt size exceeded", bigint); 10804514f5e3Sopenharmony_ci } 10814514f5e3Sopenharmony_ci 10824514f5e3Sopenharmony_ci if (base->GetLength() == 1 && base->GetDigit(0) == 2) { // 2 : We use fast path processing 2 ^ n 10834514f5e3Sopenharmony_ci uint32_t needLength = expValue / DATEBITS + 1; 10844514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = CreateBigint(thread, needLength); 10854514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 10864514f5e3Sopenharmony_ci uint32_t value = 1U << (expValue % DATEBITS); 10874514f5e3Sopenharmony_ci bigint->SetDigit(needLength - 1, value); 10884514f5e3Sopenharmony_ci if (base->GetSign()) { 10894514f5e3Sopenharmony_ci bigint->SetSign(static_cast<bool>(expValue & 1)); 10904514f5e3Sopenharmony_ci } 10914514f5e3Sopenharmony_ci return bigint; 10924514f5e3Sopenharmony_ci } 10934514f5e3Sopenharmony_ci JSMutableHandle<BigInt> result(thread, JSTaggedValue::Null()); 10944514f5e3Sopenharmony_ci JSMutableHandle<BigInt> temp(thread, base); 10954514f5e3Sopenharmony_ci if (expValue & 1) { 10964514f5e3Sopenharmony_ci result.Update(base); 10974514f5e3Sopenharmony_ci } 10984514f5e3Sopenharmony_ci expValue >>= 1; 10994514f5e3Sopenharmony_ci for (; expValue; expValue >>= 1) { 11004514f5e3Sopenharmony_ci temp.Update(BigInt::Multiply(thread, temp, temp)); 11014514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 11024514f5e3Sopenharmony_ci if (expValue & 1) { 11034514f5e3Sopenharmony_ci if (result.GetTaggedValue().IsNull()) { 11044514f5e3Sopenharmony_ci result.Update(temp); 11054514f5e3Sopenharmony_ci } else { 11064514f5e3Sopenharmony_ci result.Update(BigInt::Multiply(thread, result, temp)); 11074514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 11084514f5e3Sopenharmony_ci } 11094514f5e3Sopenharmony_ci } 11104514f5e3Sopenharmony_ci } 11114514f5e3Sopenharmony_ci ASSERT(result.GetTaggedValue().IsBigInt()); 11124514f5e3Sopenharmony_ci return result; 11134514f5e3Sopenharmony_ci} 11144514f5e3Sopenharmony_ci 11154514f5e3Sopenharmony_cistd::tuple<uint32_t, uint32_t> BigInt::Mul(uint32_t x, uint32_t y) 11164514f5e3Sopenharmony_ci{ 11174514f5e3Sopenharmony_ci uint32_t lowBitX = x & HALFDATEMASK; 11184514f5e3Sopenharmony_ci uint32_t highBitX = x >> HALFDATEBITS; 11194514f5e3Sopenharmony_ci uint32_t lowBitY = y & HALFDATEMASK; 11204514f5e3Sopenharmony_ci uint32_t highBitY = y >> HALFDATEBITS; 11214514f5e3Sopenharmony_ci // {highBitX lowBitX} * {highBitY lowBitY} 11224514f5e3Sopenharmony_ci uint32_t lowRes = lowBitX * lowBitY; 11234514f5e3Sopenharmony_ci uint32_t highRes = highBitX * highBitY; 11244514f5e3Sopenharmony_ci uint32_t midRes1 = lowBitX * highBitY; 11254514f5e3Sopenharmony_ci uint32_t midRes2 = highBitX * lowBitY; 11264514f5e3Sopenharmony_ci 11274514f5e3Sopenharmony_ci uint32_t carry = 0; 11284514f5e3Sopenharmony_ci uint32_t low = BigIntHelper::AddHelper( 11294514f5e3Sopenharmony_ci BigIntHelper::AddHelper(lowRes, midRes1 << HALFDATEBITS, carry), midRes2 << HALFDATEBITS, carry); 11304514f5e3Sopenharmony_ci uint32_t high = (midRes1 >> HALFDATEBITS) + (midRes2 >> HALFDATEBITS) + highRes + carry; 11314514f5e3Sopenharmony_ci 11324514f5e3Sopenharmony_ci return std::make_tuple(high, low); 11334514f5e3Sopenharmony_ci} 11344514f5e3Sopenharmony_ci 11354514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 11364514f5e3Sopenharmony_ci{ 11374514f5e3Sopenharmony_ci if (x->IsZero()) { 11384514f5e3Sopenharmony_ci return x; 11394514f5e3Sopenharmony_ci } 11404514f5e3Sopenharmony_ci if (y->IsZero()) { 11414514f5e3Sopenharmony_ci return y; 11424514f5e3Sopenharmony_ci } 11434514f5e3Sopenharmony_ci uint32_t needLength = x->GetLength() + y->GetLength(); 11444514f5e3Sopenharmony_ci JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, needLength); 11454514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 11464514f5e3Sopenharmony_ci // the algorithm here is similar to the way we use paper money to calculate multiplication. 11474514f5e3Sopenharmony_ci // Generally, we first calculate the partial product, and then add up to get the result. 11484514f5e3Sopenharmony_ci // The only difference here is that multiplication and addition are calculated synchronously 11494514f5e3Sopenharmony_ci for (uint32_t i = 0; i < x->GetLength(); i++) { 11504514f5e3Sopenharmony_ci uint32_t xVal = x->GetDigit(i); 11514514f5e3Sopenharmony_ci // If the current multiplier is 0, we will skip this round of calculation to improve performance. 11524514f5e3Sopenharmony_ci // If we do not skip, the correctness of the calculation will not be affected 11534514f5e3Sopenharmony_ci if (xVal == 0) { 11544514f5e3Sopenharmony_ci continue; 11554514f5e3Sopenharmony_ci } 11564514f5e3Sopenharmony_ci uint32_t carry = 0; 11574514f5e3Sopenharmony_ci uint32_t high = 0; 11584514f5e3Sopenharmony_ci uint32_t index = i; 11594514f5e3Sopenharmony_ci for (uint32_t j = 0; j < y->GetLength(); j++) { 11604514f5e3Sopenharmony_ci uint32_t currentCarry = 0; 11614514f5e3Sopenharmony_ci uint32_t value = bigint->GetDigit(index); 11624514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, high, currentCarry); 11634514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, carry, currentCarry); 11644514f5e3Sopenharmony_ci 11654514f5e3Sopenharmony_ci uint32_t low; 11664514f5e3Sopenharmony_ci std::tie(high, low) = Mul(xVal, y->GetDigit(j)); 11674514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, low, currentCarry); 11684514f5e3Sopenharmony_ci bigint->SetDigit(index, value); 11694514f5e3Sopenharmony_ci carry = currentCarry; 11704514f5e3Sopenharmony_ci index++; 11714514f5e3Sopenharmony_ci } 11724514f5e3Sopenharmony_ci while (carry != 0 || high != 0) { 11734514f5e3Sopenharmony_ci ASSERT(index < bigint->GetLength()); 11744514f5e3Sopenharmony_ci uint32_t value = bigint->GetDigit(index); 11754514f5e3Sopenharmony_ci uint32_t currentCarry = 0; 11764514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, high, currentCarry); 11774514f5e3Sopenharmony_ci high = 0; 11784514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, carry, currentCarry); 11794514f5e3Sopenharmony_ci bigint->SetDigit(index, value); 11804514f5e3Sopenharmony_ci carry = currentCarry; 11814514f5e3Sopenharmony_ci index++; 11824514f5e3Sopenharmony_ci } 11834514f5e3Sopenharmony_ci } 11844514f5e3Sopenharmony_ci 11854514f5e3Sopenharmony_ci bigint->SetSign(x->GetSign() != y->GetSign()); 11864514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, bigint); 11874514f5e3Sopenharmony_ci} 11884514f5e3Sopenharmony_ci 11894514f5e3Sopenharmony_civoid BigIntHelper::DeZero(CString &a) 11904514f5e3Sopenharmony_ci{ 11914514f5e3Sopenharmony_ci size_t count = 0; 11924514f5e3Sopenharmony_ci while (count < a.size() && a[count] == '0') { 11934514f5e3Sopenharmony_ci count++; 11944514f5e3Sopenharmony_ci } 11954514f5e3Sopenharmony_ci if (count == a.size()) { 11964514f5e3Sopenharmony_ci a = "0"; 11974514f5e3Sopenharmony_ci } else { 11984514f5e3Sopenharmony_ci a = a.substr(count); 11994514f5e3Sopenharmony_ci } 12004514f5e3Sopenharmony_ci} 12014514f5e3Sopenharmony_ci 12024514f5e3Sopenharmony_ciComparisonResult BigInt::AbsolutelyCompare(const BigInt *x, const BigInt *y) 12034514f5e3Sopenharmony_ci{ 12044514f5e3Sopenharmony_ci uint32_t xLen = x->GetLength(); 12054514f5e3Sopenharmony_ci uint32_t yLen = y->GetLength(); 12064514f5e3Sopenharmony_ci if (xLen > yLen) { 12074514f5e3Sopenharmony_ci return ComparisonResult::GREAT; 12084514f5e3Sopenharmony_ci } else if (xLen < yLen) { 12094514f5e3Sopenharmony_ci return ComparisonResult::LESS; 12104514f5e3Sopenharmony_ci } else { 12114514f5e3Sopenharmony_ci int index = static_cast<int>(xLen) - 1; 12124514f5e3Sopenharmony_ci for (; index >= 0; --index) { 12134514f5e3Sopenharmony_ci if (x->GetDigit(index) != y->GetDigit(index)) { 12144514f5e3Sopenharmony_ci break; 12154514f5e3Sopenharmony_ci } 12164514f5e3Sopenharmony_ci } 12174514f5e3Sopenharmony_ci if (index < 0) { 12184514f5e3Sopenharmony_ci return ComparisonResult::EQUAL; 12194514f5e3Sopenharmony_ci } 12204514f5e3Sopenharmony_ci return x->GetDigit(index) > y->GetDigit(index) ? ComparisonResult::GREAT : ComparisonResult::LESS; 12214514f5e3Sopenharmony_ci } 12224514f5e3Sopenharmony_ci} 12234514f5e3Sopenharmony_ci 12244514f5e3Sopenharmony_ciuint32_t BigInt::DivideAndRemainder(uint32_t highBit, uint32_t lowBit, uint32_t divisor, uint32_t& remainder) 12254514f5e3Sopenharmony_ci{ 12264514f5e3Sopenharmony_ci uint32_t leadingZeros = base::CountLeadingZeros(divisor); 12274514f5e3Sopenharmony_ci // Before calculating, we need to align the operands to the left 12284514f5e3Sopenharmony_ci divisor <<= leadingZeros; 12294514f5e3Sopenharmony_ci uint32_t lowDividend = lowBit << leadingZeros; 12304514f5e3Sopenharmony_ci uint32_t highDividend = highBit; 12314514f5e3Sopenharmony_ci if (leadingZeros != 0) { 12324514f5e3Sopenharmony_ci // highBit is the remainder of the last calculation, which must be less than or equal to the divisor, 12334514f5e3Sopenharmony_ci // so high << leadingZeros will not lose the significant bit 12344514f5e3Sopenharmony_ci highDividend = (highBit << leadingZeros) | (lowBit >> (DATEBITS - leadingZeros)); 12354514f5e3Sopenharmony_ci } 12364514f5e3Sopenharmony_ci uint32_t highDivisor = divisor >> HALFDATEBITS; 12374514f5e3Sopenharmony_ci uint32_t lowDivisor = divisor & HALFDATEMASK; 12384514f5e3Sopenharmony_ci uint32_t lowDividend1 = lowDividend >> HALFDATEBITS; 12394514f5e3Sopenharmony_ci uint32_t lowDividend2 = lowDividend & HALFDATEMASK; 12404514f5e3Sopenharmony_ci uint32_t highQuotient = highDividend / highDivisor; 12414514f5e3Sopenharmony_ci uint32_t tempRemainder = highDividend - highQuotient * highDivisor; 12424514f5e3Sopenharmony_ci 12434514f5e3Sopenharmony_ci // Similar to the ordinary division calculation, here we use HALFUINT32VALUE as the carry unit 12444514f5e3Sopenharmony_ci // Calculate high order results first 12454514f5e3Sopenharmony_ci while (highQuotient >= HALFUINT32VALUE || 12464514f5e3Sopenharmony_ci highQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend1) { 12474514f5e3Sopenharmony_ci highQuotient--; 12484514f5e3Sopenharmony_ci tempRemainder += highDivisor; 12494514f5e3Sopenharmony_ci if (tempRemainder >= HALFUINT32VALUE) { 12504514f5e3Sopenharmony_ci break; 12514514f5e3Sopenharmony_ci } 12524514f5e3Sopenharmony_ci } 12534514f5e3Sopenharmony_ci uint32_t tempLowDividend = highDividend * HALFUINT32VALUE + lowDividend1 - highQuotient * divisor; 12544514f5e3Sopenharmony_ci uint32_t lowQuotient = tempLowDividend / highDivisor; 12554514f5e3Sopenharmony_ci tempRemainder = tempLowDividend - lowQuotient * highDivisor; 12564514f5e3Sopenharmony_ci 12574514f5e3Sopenharmony_ci // Then calculate the low order result 12584514f5e3Sopenharmony_ci while (lowQuotient >= HALFUINT32VALUE || 12594514f5e3Sopenharmony_ci lowQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend2) { 12604514f5e3Sopenharmony_ci lowQuotient--; 12614514f5e3Sopenharmony_ci tempRemainder += highDivisor; 12624514f5e3Sopenharmony_ci if (tempRemainder >= HALFUINT32VALUE) { 12634514f5e3Sopenharmony_ci break; 12644514f5e3Sopenharmony_ci } 12654514f5e3Sopenharmony_ci } 12664514f5e3Sopenharmony_ci 12674514f5e3Sopenharmony_ci // In order to facilitate the calculation, we start to make left alignment 12684514f5e3Sopenharmony_ci // At this time, we need to move right to get the correct remainder 12694514f5e3Sopenharmony_ci remainder = (tempLowDividend * HALFUINT32VALUE + lowDividend2 - lowQuotient * divisor) >> leadingZeros; 12704514f5e3Sopenharmony_ci return highQuotient * HALFUINT32VALUE + lowQuotient; 12714514f5e3Sopenharmony_ci} 12724514f5e3Sopenharmony_ci 12734514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::FormatLeftShift(JSThread *thread, uint32_t shift, JSHandle<BigInt> bigint, bool neeedAddOne) 12744514f5e3Sopenharmony_ci{ 12754514f5e3Sopenharmony_ci if (!neeedAddOne && shift == 0) { 12764514f5e3Sopenharmony_ci return bigint; 12774514f5e3Sopenharmony_ci } 12784514f5e3Sopenharmony_ci uint32_t len = bigint->GetLength(); 12794514f5e3Sopenharmony_ci uint32_t needLen = len; 12804514f5e3Sopenharmony_ci if (neeedAddOne) { 12814514f5e3Sopenharmony_ci needLen += 1; 12824514f5e3Sopenharmony_ci } 12834514f5e3Sopenharmony_ci JSHandle<BigInt> result = CreateBigint(thread, needLen); 12844514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 12854514f5e3Sopenharmony_ci if (shift == 0) { 12864514f5e3Sopenharmony_ci std::copy(bigint->GetData(), bigint->GetData() + len, result->GetData()); 12874514f5e3Sopenharmony_ci } else { 12884514f5e3Sopenharmony_ci uint32_t carry = 0; 12894514f5e3Sopenharmony_ci uint32_t index = 0; 12904514f5e3Sopenharmony_ci while (index < len) { 12914514f5e3Sopenharmony_ci uint32_t value = bigint->GetDigit(index); 12924514f5e3Sopenharmony_ci result->SetDigit(index, (value << shift) | carry); 12934514f5e3Sopenharmony_ci carry = value >> (DATEBITS - shift); 12944514f5e3Sopenharmony_ci index++; 12954514f5e3Sopenharmony_ci } 12964514f5e3Sopenharmony_ci if (carry != 0) { 12974514f5e3Sopenharmony_ci ASSERT(neeedAddOne); 12984514f5e3Sopenharmony_ci result->SetDigit(index, carry); 12994514f5e3Sopenharmony_ci } 13004514f5e3Sopenharmony_ci } 13014514f5e3Sopenharmony_ci return result; 13024514f5e3Sopenharmony_ci} 13034514f5e3Sopenharmony_ci 13044514f5e3Sopenharmony_civoid BigInt::UnformattedRightShift(JSHandle<BigInt> bigint, uint32_t shift) 13054514f5e3Sopenharmony_ci{ 13064514f5e3Sopenharmony_ci RightShift(bigint, bigint, 0, shift); 13074514f5e3Sopenharmony_ci} 13084514f5e3Sopenharmony_ci 13094514f5e3Sopenharmony_cibool BigInt::SpecialMultiplyAndSub(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t q, JSHandle<BigInt> qv, 13104514f5e3Sopenharmony_ci uint32_t pos) 13114514f5e3Sopenharmony_ci{ 13124514f5e3Sopenharmony_ci uint32_t lastCarry = 0; 13134514f5e3Sopenharmony_ci uint32_t lastHigh = 0; 13144514f5e3Sopenharmony_ci uint32_t len = v->GetLength(); 13154514f5e3Sopenharmony_ci // Calculate multiplication first 13164514f5e3Sopenharmony_ci for (uint32_t i = 0; i < len; ++i) { 13174514f5e3Sopenharmony_ci uint32_t value = v->GetDigit(i); 13184514f5e3Sopenharmony_ci uint32_t carry = 0; 13194514f5e3Sopenharmony_ci uint32_t high = 0; 13204514f5e3Sopenharmony_ci std::tie(high, value) = Mul(value, q); 13214514f5e3Sopenharmony_ci // The current value plus the high and carry of the last calculation 13224514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, lastHigh, carry); 13234514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, lastCarry, carry); 13244514f5e3Sopenharmony_ci qv->SetDigit(i, value); 13254514f5e3Sopenharmony_ci // Record the new high bit and carry for the next round 13264514f5e3Sopenharmony_ci lastCarry = carry; 13274514f5e3Sopenharmony_ci lastHigh = high; 13284514f5e3Sopenharmony_ci } 13294514f5e3Sopenharmony_ci qv->SetDigit(len, lastHigh + lastCarry); 13304514f5e3Sopenharmony_ci 13314514f5e3Sopenharmony_ci // Next, subtract 13324514f5e3Sopenharmony_ci uint32_t lastBorrow = 0; 13334514f5e3Sopenharmony_ci for (uint32_t i = 0; i < qv->GetLength(); ++i) { 13344514f5e3Sopenharmony_ci uint32_t borrow = 0; 13354514f5e3Sopenharmony_ci uint32_t value = BigIntHelper::SubHelper(u->GetDigit(pos + i), qv->GetDigit(i), borrow); 13364514f5e3Sopenharmony_ci value = BigIntHelper::SubHelper(value, lastBorrow, borrow); 13374514f5e3Sopenharmony_ci u->SetDigit(pos + i, value); 13384514f5e3Sopenharmony_ci lastBorrow = borrow; 13394514f5e3Sopenharmony_ci } 13404514f5e3Sopenharmony_ci 13414514f5e3Sopenharmony_ci return lastBorrow > 0; 13424514f5e3Sopenharmony_ci} 13434514f5e3Sopenharmony_ci 13444514f5e3Sopenharmony_ciuint32_t BigInt::SpecialAdd(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t pos) 13454514f5e3Sopenharmony_ci{ 13464514f5e3Sopenharmony_ci uint32_t lastCarry = 0; 13474514f5e3Sopenharmony_ci for (uint32_t i = 0; i < v->GetLength(); ++i) { 13484514f5e3Sopenharmony_ci uint32_t carry = 0; 13494514f5e3Sopenharmony_ci uint32_t value = BigIntHelper::AddHelper(u->GetDigit(pos + i), v->GetDigit(i), carry); 13504514f5e3Sopenharmony_ci value = BigIntHelper::AddHelper(value, lastCarry, carry); 13514514f5e3Sopenharmony_ci u->SetDigit(pos + i, value); 13524514f5e3Sopenharmony_ci lastCarry = carry; 13534514f5e3Sopenharmony_ci } 13544514f5e3Sopenharmony_ci return lastCarry; 13554514f5e3Sopenharmony_ci} 13564514f5e3Sopenharmony_ci 13574514f5e3Sopenharmony_ciuint32_t BigInt::ImproveAccuracy(uint32_t vHighest, uint32_t vHighestNext, uint32_t UHighest, 13584514f5e3Sopenharmony_ci uint32_t UHighestNext, uint32_t q) 13594514f5e3Sopenharmony_ci{ 13604514f5e3Sopenharmony_ci uint32_t high = 0; 13614514f5e3Sopenharmony_ci uint32_t low = 0; 13624514f5e3Sopenharmony_ci std::tie(high, low) = Mul(q, vHighestNext); 13634514f5e3Sopenharmony_ci while (high > UHighest || (high == UHighest && low > UHighestNext)) { 13644514f5e3Sopenharmony_ci q--; 13654514f5e3Sopenharmony_ci UHighest += vHighest; 13664514f5e3Sopenharmony_ci // if r is less than the current base, continue the next round of inspection. Here, 13674514f5e3Sopenharmony_ci // we confirm whether r is greater than the current base by judging whether r overflows 13684514f5e3Sopenharmony_ci if (UHighest < vHighest) { 13694514f5e3Sopenharmony_ci break; 13704514f5e3Sopenharmony_ci } 13714514f5e3Sopenharmony_ci std::tie(high, low) = Mul(q, vHighestNext); 13724514f5e3Sopenharmony_ci } 13734514f5e3Sopenharmony_ci return q; 13744514f5e3Sopenharmony_ci} 13754514f5e3Sopenharmony_ci 13764514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::DivideAndRemainderWithBigintDivisor(JSThread *thread, JSHandle<BigInt> dividend, 13774514f5e3Sopenharmony_ci JSHandle<BigInt> divisor, 13784514f5e3Sopenharmony_ci JSMutableHandle<BigInt> &remainder) 13794514f5e3Sopenharmony_ci{ 13804514f5e3Sopenharmony_ci uint32_t divisorLen = divisor->GetLength(); 13814514f5e3Sopenharmony_ci // the length of the quota is the length of the dividend minus the divisor 13824514f5e3Sopenharmony_ci uint32_t quotientLen = dividend->GetLength() - divisorLen; 13834514f5e3Sopenharmony_ci JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null()); 13844514f5e3Sopenharmony_ci if (remainder.GetTaggedValue().IsNull()) { 13854514f5e3Sopenharmony_ci quotient.Update(CreateBigint(thread, quotientLen + 1)); 13864514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 13874514f5e3Sopenharmony_ci } 13884514f5e3Sopenharmony_ci // format the divisor and dividend so that the highest order of the divisor is 13894514f5e3Sopenharmony_ci // greater than or equal to half of uint32_t 13904514f5e3Sopenharmony_ci ASSERT(divisorLen > 0); 13914514f5e3Sopenharmony_ci uint32_t leadingZeros = base::CountLeadingZeros(divisor->GetDigit(divisorLen - 1)); 13924514f5e3Sopenharmony_ci JSHandle<BigInt> v = FormatLeftShift(thread, leadingZeros, divisor, false); 13934514f5e3Sopenharmony_ci JSHandle<BigInt> u = FormatLeftShift(thread, leadingZeros, dividend, true); 13944514f5e3Sopenharmony_ci // qv is used to store the result of quotient * divisor of each round 13954514f5e3Sopenharmony_ci JSHandle<BigInt> qv = CreateBigint(thread, divisorLen + 1); 13964514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 13974514f5e3Sopenharmony_ci uint32_t vHighest = v->GetDigit(divisorLen - 1); 13984514f5e3Sopenharmony_ci for (int i = static_cast<int>(quotientLen); i >= 0; --i) { 13994514f5e3Sopenharmony_ci uint32_t currentUHighest = u->GetDigit(i + divisorLen); 14004514f5e3Sopenharmony_ci uint32_t r = 0; 14014514f5e3Sopenharmony_ci uint32_t q = DivideAndRemainder(currentUHighest, u->GetDigit(i + divisorLen - 1), vHighest, r); 14024514f5e3Sopenharmony_ci // VHighest = currentUHighest means that q may be equal to the current base 14034514f5e3Sopenharmony_ci // In the current program, the current base is the maximum value of uint32 plus 1 14044514f5e3Sopenharmony_ci if (vHighest == currentUHighest) { 14054514f5e3Sopenharmony_ci q = std::numeric_limits<uint32_t>::max(); 14064514f5e3Sopenharmony_ci } else { 14074514f5e3Sopenharmony_ci uint32_t vHighestNext = v->GetDigit(divisorLen - 2); // 2 : Get the second most significant bit 14084514f5e3Sopenharmony_ci uint32_t currentUHighestNext = u->GetDigit(i + divisorLen - 2); // 2 : ditto 14094514f5e3Sopenharmony_ci 14104514f5e3Sopenharmony_ci // The following operations will make q only 1 greater than the value we want in most cases, 14114514f5e3Sopenharmony_ci // and will not be less than it 14124514f5e3Sopenharmony_ci q = ImproveAccuracy(vHighest, vHighestNext, r, currentUHighestNext, q); 14134514f5e3Sopenharmony_ci } 14144514f5e3Sopenharmony_ci // multiplication and subtraction 14154514f5e3Sopenharmony_ci if (SpecialMultiplyAndSub(u, v, q, qv, i)) { 14164514f5e3Sopenharmony_ci q--; 14174514f5e3Sopenharmony_ci uint32_t carry = SpecialAdd(u, v, i); 14184514f5e3Sopenharmony_ci u->SetDigit(i + divisorLen, u->GetDigit(i + divisorLen) + carry); 14194514f5e3Sopenharmony_ci } 14204514f5e3Sopenharmony_ci if (remainder.GetTaggedValue().IsNull()) { 14214514f5e3Sopenharmony_ci quotient->SetDigit(i, q); 14224514f5e3Sopenharmony_ci } 14234514f5e3Sopenharmony_ci } 14244514f5e3Sopenharmony_ci if (!remainder.GetTaggedValue().IsNull()) { 14254514f5e3Sopenharmony_ci // at the beginning of this procedure, we performed the left shift operation. 14264514f5e3Sopenharmony_ci // Here, we get the correct result by shifting the same number of digits to the right 14274514f5e3Sopenharmony_ci UnformattedRightShift(u, leadingZeros); 14284514f5e3Sopenharmony_ci remainder.Update(u); 14294514f5e3Sopenharmony_ci } 14304514f5e3Sopenharmony_ci return quotient; 14314514f5e3Sopenharmony_ci} 14324514f5e3Sopenharmony_ci 14334514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::DivideAndRemainderWithUint32Divisor(JSThread *thread, JSHandle<BigInt> dividend, 14344514f5e3Sopenharmony_ci uint32_t divisor, JSMutableHandle<BigInt> &remainder) 14354514f5e3Sopenharmony_ci{ 14364514f5e3Sopenharmony_ci uint32_t r = 0; 14374514f5e3Sopenharmony_ci JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null()); 14384514f5e3Sopenharmony_ci if (!remainder.GetTaggedValue().IsNull()) { 14394514f5e3Sopenharmony_ci for (int i = static_cast<int>(dividend->GetLength()) - 1; i >= 0; --i) { 14404514f5e3Sopenharmony_ci DivideAndRemainder(r, dividend->GetDigit(i), divisor, r); 14414514f5e3Sopenharmony_ci remainder.Update(Uint32ToBigInt(thread, r)); 14424514f5e3Sopenharmony_ci } 14434514f5e3Sopenharmony_ci } else { 14444514f5e3Sopenharmony_ci quotient.Update(CreateBigint(thread, dividend->GetLength())); 14454514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 14464514f5e3Sopenharmony_ci for (int i = static_cast<int>(dividend->GetLength()) - 1; i >= 0; --i) { 14474514f5e3Sopenharmony_ci uint32_t q = DivideAndRemainder(r, dividend->GetDigit(i), divisor, r); 14484514f5e3Sopenharmony_ci quotient->SetDigit(i, q); 14494514f5e3Sopenharmony_ci } 14504514f5e3Sopenharmony_ci } 14514514f5e3Sopenharmony_ci return quotient; 14524514f5e3Sopenharmony_ci} 14534514f5e3Sopenharmony_ci 14544514f5e3Sopenharmony_ci// The algorithm here refers to algorithm D in Volume 2 of <The Art of Computer Programming> 14554514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y) 14564514f5e3Sopenharmony_ci{ 14574514f5e3Sopenharmony_ci if (y->IsZero()) { 14584514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 14594514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint); 14604514f5e3Sopenharmony_ci } 14614514f5e3Sopenharmony_ci // returns 0 if x is less than y 14624514f5e3Sopenharmony_ci JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null()); 14634514f5e3Sopenharmony_ci bool sign = x->GetSign() != y->GetSign(); 14644514f5e3Sopenharmony_ci ComparisonResult compare = AbsolutelyCompare(*x, *y); 14654514f5e3Sopenharmony_ci if (compare == ComparisonResult::LESS) { 14664514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0); 14674514f5e3Sopenharmony_ci } 14684514f5e3Sopenharmony_ci if (compare == ComparisonResult::EQUAL) { 14694514f5e3Sopenharmony_ci quotient.Update(Int32ToBigInt(thread, 1)); 14704514f5e3Sopenharmony_ci quotient->SetSign(sign); 14714514f5e3Sopenharmony_ci return quotient; 14724514f5e3Sopenharmony_ci } 14734514f5e3Sopenharmony_ci // if y is 1, return +x or -x 14744514f5e3Sopenharmony_ci if (y->IsUint32() && y->GetDigit(0) == 1) { 14754514f5e3Sopenharmony_ci if (sign == x->GetSign()) { 14764514f5e3Sopenharmony_ci return x; 14774514f5e3Sopenharmony_ci } 14784514f5e3Sopenharmony_ci return UnaryMinus(thread, x); 14794514f5e3Sopenharmony_ci } 14804514f5e3Sopenharmony_ci JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Null()); 14814514f5e3Sopenharmony_ci if (y->IsUint32()) { 14824514f5e3Sopenharmony_ci // When the divisor is uint32_t, we have a faster and simpler algorithm to calculate 14834514f5e3Sopenharmony_ci quotient.Update(DivideAndRemainderWithUint32Divisor(thread, x, y->GetDigit(0), remainder)); 14844514f5e3Sopenharmony_ci } else { 14854514f5e3Sopenharmony_ci ASSERT(y->GetLength() >= 1); // 1 : Entering the current branch length must be greater than 1 14864514f5e3Sopenharmony_ci JSHandle<BigInt> newBigint = DivideAndRemainderWithBigintDivisor(thread, x, y, remainder); 14874514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 14884514f5e3Sopenharmony_ci quotient.Update(newBigint); 14894514f5e3Sopenharmony_ci } 14904514f5e3Sopenharmony_ci ASSERT(quotient.GetTaggedValue().IsBigInt()); 14914514f5e3Sopenharmony_ci quotient->SetSign(sign); 14924514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, quotient); 14934514f5e3Sopenharmony_ci} 14944514f5e3Sopenharmony_ci 14954514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d) 14964514f5e3Sopenharmony_ci{ 14974514f5e3Sopenharmony_ci if (d->IsZero()) { 14984514f5e3Sopenharmony_ci JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception()); 14994514f5e3Sopenharmony_ci THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint); 15004514f5e3Sopenharmony_ci } 15014514f5e3Sopenharmony_ci ComparisonResult compare = AbsolutelyCompare(*n, *d); 15024514f5e3Sopenharmony_ci if (n->IsZero() || compare == ComparisonResult::LESS) { 15034514f5e3Sopenharmony_ci return n; 15044514f5e3Sopenharmony_ci } 15054514f5e3Sopenharmony_ci if (compare == ComparisonResult::EQUAL || (d->IsUint32() && d->GetDigit(0) == 1)) { 15064514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0); 15074514f5e3Sopenharmony_ci } 15084514f5e3Sopenharmony_ci JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Undefined()); 15094514f5e3Sopenharmony_ci if (d->IsUint32()) { 15104514f5e3Sopenharmony_ci // When the divisor is uint32_t, we have a faster and simpler algorithm to calculate 15114514f5e3Sopenharmony_ci DivideAndRemainderWithUint32Divisor(thread, n, d->GetDigit(0), remainder); 15124514f5e3Sopenharmony_ci } else { 15134514f5e3Sopenharmony_ci ASSERT(d->GetLength() > 1); // 1 : Entering the current branch length must be greater than 1 15144514f5e3Sopenharmony_ci DivideAndRemainderWithBigintDivisor(thread, n, d, remainder); 15154514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 15164514f5e3Sopenharmony_ci } 15174514f5e3Sopenharmony_ci ASSERT(remainder.GetTaggedValue().IsBigInt()); 15184514f5e3Sopenharmony_ci remainder->SetSign(n->GetSign()); 15194514f5e3Sopenharmony_ci return BigIntHelper::RightTruncate(thread, remainder); 15204514f5e3Sopenharmony_ci} 15214514f5e3Sopenharmony_ci 15224514f5e3Sopenharmony_ciJSHandle<BigInt> BigInt::FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal) 15234514f5e3Sopenharmony_ci{ 15244514f5e3Sopenharmony_ci JSHandle<BigInt> remainder = Remainder(thread, leftVal, rightVal); 15254514f5e3Sopenharmony_ci RETURN_HANDLE_IF_ABRUPT_COMPLETION(BigInt, thread); 15264514f5e3Sopenharmony_ci if (leftVal->GetSign() && !remainder->IsZero()) { 15274514f5e3Sopenharmony_ci return Add(thread, remainder, rightVal); 15284514f5e3Sopenharmony_ci } 15294514f5e3Sopenharmony_ci return remainder; 15304514f5e3Sopenharmony_ci} 15314514f5e3Sopenharmony_ci 15324514f5e3Sopenharmony_ciJSTaggedValue BigInt::AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint) 15334514f5e3Sopenharmony_ci{ 15344514f5e3Sopenharmony_ci JSTaggedNumber number = JSTaggedValue::ToNumber(thread, bits); 15354514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15364514f5e3Sopenharmony_ci int64_t bit = base::NumberHelper::DoubleToInt64(number.GetNumber()); 15374514f5e3Sopenharmony_ci if (bit == 0) { 15384514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0).GetTaggedValue(); 15394514f5e3Sopenharmony_ci } 15404514f5e3Sopenharmony_ci if (bigint->IsZero()) { 15414514f5e3Sopenharmony_ci return bigint.GetTaggedValue(); 15424514f5e3Sopenharmony_ci } 15434514f5e3Sopenharmony_ci JSHandle<BigInt> exponent = Uint64ToBigInt(thread, bit); 15444514f5e3Sopenharmony_ci JSHandle<BigInt> base = Int64ToBigInt(thread, 2); // 2 : base value 15454514f5e3Sopenharmony_ci if (bit >= kMaxLengthBits && !bigint->GetSign()) { 15464514f5e3Sopenharmony_ci return bigint.GetTaggedValue(); 15474514f5e3Sopenharmony_ci } 15484514f5e3Sopenharmony_ci JSHandle<BigInt> tValue = Exponentiate(thread, base, exponent); 15494514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15504514f5e3Sopenharmony_ci return FloorMod(thread, bigint, tValue).GetTaggedValue(); 15514514f5e3Sopenharmony_ci} 15524514f5e3Sopenharmony_ci 15534514f5e3Sopenharmony_ciJSTaggedValue BigInt::AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint) 15544514f5e3Sopenharmony_ci{ 15554514f5e3Sopenharmony_ci JSTaggedNumber number = JSTaggedValue::ToNumber(thread, bits); 15564514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15574514f5e3Sopenharmony_ci int64_t bit = base::NumberHelper::DoubleToInt64(number.GetNumber()); 15584514f5e3Sopenharmony_ci if (bit == 0) { 15594514f5e3Sopenharmony_ci return Int32ToBigInt(thread, 0).GetTaggedValue(); 15604514f5e3Sopenharmony_ci } 15614514f5e3Sopenharmony_ci if (bigint->IsZero()) { 15624514f5e3Sopenharmony_ci return bigint.GetTaggedValue(); 15634514f5e3Sopenharmony_ci } 15644514f5e3Sopenharmony_ci JSHandle<BigInt> exp = Int64ToBigInt(thread, bit); 15654514f5e3Sopenharmony_ci JSHandle<BigInt> exponent = Int64ToBigInt(thread, bit - 1); 15664514f5e3Sopenharmony_ci JSHandle<BigInt> base = Int64ToBigInt(thread, 2); // 2 : base value 15674514f5e3Sopenharmony_ci if (bit >= kMaxLengthBits && !bigint->GetSign()) { 15684514f5e3Sopenharmony_ci return bigint.GetTaggedValue(); 15694514f5e3Sopenharmony_ci } 15704514f5e3Sopenharmony_ci JSHandle<BigInt> tValue = Exponentiate(thread, base, exp); 15714514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15724514f5e3Sopenharmony_ci JSHandle<BigInt> modValue = FloorMod(thread, bigint, tValue); 15734514f5e3Sopenharmony_ci JSHandle<BigInt> resValue = Exponentiate(thread, base, exponent); 15744514f5e3Sopenharmony_ci RETURN_EXCEPTION_IF_ABRUPT_COMPLETION(thread); 15754514f5e3Sopenharmony_ci // If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return (mod). 15764514f5e3Sopenharmony_ci if (Compare(*resValue, *modValue) != ComparisonResult::GREAT) { 15774514f5e3Sopenharmony_ci return Subtract(thread, modValue, tValue).GetTaggedValue(); 15784514f5e3Sopenharmony_ci } 15794514f5e3Sopenharmony_ci return modValue.GetTaggedValue(); 15804514f5e3Sopenharmony_ci} 15814514f5e3Sopenharmony_ci 15824514f5e3Sopenharmony_cistatic JSTaggedNumber CalculateNumber(const uint64_t &sign, const uint64_t &mantissa, uint64_t &exponent) 15834514f5e3Sopenharmony_ci{ 15844514f5e3Sopenharmony_ci exponent = (exponent + base::DOUBLE_EXPONENT_BIAS) << base::DOUBLE_SIGNIFICAND_SIZE; 15854514f5e3Sopenharmony_ci uint64_t doubleBit = sign | exponent | mantissa; 15864514f5e3Sopenharmony_ci double res = 0; 15874514f5e3Sopenharmony_ci if (memcpy_s(&res, sizeof(res), &doubleBit, sizeof(doubleBit)) != EOK) { 15884514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "memcpy_s failed"; 15894514f5e3Sopenharmony_ci UNREACHABLE(); 15904514f5e3Sopenharmony_ci } 15914514f5e3Sopenharmony_ci return JSTaggedNumber(res); 15924514f5e3Sopenharmony_ci} 15934514f5e3Sopenharmony_ci 15944514f5e3Sopenharmony_cistatic JSTaggedNumber Rounding(const uint64_t &sign, uint64_t &mantissa, uint64_t &exponent, bool needRound) 15954514f5e3Sopenharmony_ci{ 15964514f5e3Sopenharmony_ci if (needRound || (mantissa & 1) == 1) { 15974514f5e3Sopenharmony_ci ++mantissa; 15984514f5e3Sopenharmony_ci if ((mantissa >> base::DOUBLE_SIGNIFICAND_SIZE) != 0) { 15994514f5e3Sopenharmony_ci mantissa = 0; 16004514f5e3Sopenharmony_ci exponent++; 16014514f5e3Sopenharmony_ci if (exponent > base::DOUBLE_EXPONENT_BIAS) { 16024514f5e3Sopenharmony_ci return JSTaggedNumber(sign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY); 16034514f5e3Sopenharmony_ci } 16044514f5e3Sopenharmony_ci } 16054514f5e3Sopenharmony_ci } 16064514f5e3Sopenharmony_ci return CalculateNumber(sign, mantissa, exponent); 16074514f5e3Sopenharmony_ci} 16084514f5e3Sopenharmony_ci 16094514f5e3Sopenharmony_ciJSTaggedNumber BigInt::BigIntToNumber(JSHandle<BigInt> bigint) 16104514f5e3Sopenharmony_ci{ 16114514f5e3Sopenharmony_ci if (bigint->IsZero()) { 16124514f5e3Sopenharmony_ci return JSTaggedNumber(0); 16134514f5e3Sopenharmony_ci } 16144514f5e3Sopenharmony_ci uint32_t bigintLen = bigint->GetLength(); 16154514f5e3Sopenharmony_ci ASSERT(bigintLen > 0); 16164514f5e3Sopenharmony_ci uint32_t BigintHead = bigint->GetDigit(bigintLen - 1); 16174514f5e3Sopenharmony_ci uint32_t leadingZeros = base::CountLeadingZeros(BigintHead); 16184514f5e3Sopenharmony_ci int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS - leadingZeros); 16194514f5e3Sopenharmony_ci // if Significant bits greater than 1024 then double is infinity 16204514f5e3Sopenharmony_ci bool bigintSign = bigint->GetSign(); 16214514f5e3Sopenharmony_ci if (bigintBitLen > (base::DOUBLE_EXPONENT_BIAS + 1)) { 16224514f5e3Sopenharmony_ci return JSTaggedNumber(bigintSign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY); 16234514f5e3Sopenharmony_ci } 16244514f5e3Sopenharmony_ci uint64_t sign = bigintSign ? 1ULL << 63 : 0; // 63 : Set the sign bit of sign to 1 16254514f5e3Sopenharmony_ci int needMoveBit = static_cast<int>(leadingZeros + BigInt::DATEBITS + 1); 16264514f5e3Sopenharmony_ci // Align to the most significant bit, then right shift 12 bits so that the head of the mantissa is in place 16274514f5e3Sopenharmony_ci uint64_t mantissa = (needMoveBit == 64) ? 0 : 16284514f5e3Sopenharmony_ci ((static_cast<uint64_t>(BigintHead) << needMoveBit) >> 12); // 12 mantissa// just has 52 bits 16294514f5e3Sopenharmony_ci int remainMantissaBits = needMoveBit - 12; 16304514f5e3Sopenharmony_ci ASSERT(bigintBitLen > 0); 16314514f5e3Sopenharmony_ci uint64_t exponent = static_cast<uint64_t>(bigintBitLen - 1); 16324514f5e3Sopenharmony_ci int index = static_cast<int>(bigintLen - 1); 16334514f5e3Sopenharmony_ci uint32_t digit = 0; 16344514f5e3Sopenharmony_ci if (index > 0) { 16354514f5e3Sopenharmony_ci digit = bigint->GetDigit(--index); 16364514f5e3Sopenharmony_ci } else { 16374514f5e3Sopenharmony_ci return CalculateNumber(sign, mantissa, exponent); 16384514f5e3Sopenharmony_ci } 16394514f5e3Sopenharmony_ci // pad unset mantissa 16404514f5e3Sopenharmony_ci if (static_cast<uint32_t>(remainMantissaBits) >= BigInt::DATEBITS) { 16414514f5e3Sopenharmony_ci mantissa |= (static_cast<uint64_t>(digit) << (remainMantissaBits - BigInt::DATEBITS)); 16424514f5e3Sopenharmony_ci remainMantissaBits -= BigInt::DATEBITS; 16434514f5e3Sopenharmony_ci index--; 16444514f5e3Sopenharmony_ci } 16454514f5e3Sopenharmony_ci if (remainMantissaBits > 0 && index >= 0) { 16464514f5e3Sopenharmony_ci digit = bigint->GetDigit(index); 16474514f5e3Sopenharmony_ci mantissa |= (static_cast<uint64_t>(digit) >> (BigInt::DATEBITS - remainMantissaBits)); 16484514f5e3Sopenharmony_ci remainMantissaBits -= BigInt::DATEBITS; 16494514f5e3Sopenharmony_ci } 16504514f5e3Sopenharmony_ci // After the mantissa is filled, if the bits of bigint have not been used up, consider the rounding problem 16514514f5e3Sopenharmony_ci // The remaining bits of the current digit 16524514f5e3Sopenharmony_ci if (remainMantissaBits > 0) { 16534514f5e3Sopenharmony_ci return CalculateNumber(sign, mantissa, exponent); 16544514f5e3Sopenharmony_ci } 16554514f5e3Sopenharmony_ci int remainDigitBits = 0; 16564514f5e3Sopenharmony_ci if (remainMantissaBits < 0) { 16574514f5e3Sopenharmony_ci remainDigitBits = -remainMantissaBits; 16584514f5e3Sopenharmony_ci } else { 16594514f5e3Sopenharmony_ci if (index <= 0) { 16604514f5e3Sopenharmony_ci return CalculateNumber(sign, mantissa, exponent); 16614514f5e3Sopenharmony_ci } 16624514f5e3Sopenharmony_ci digit = bigint->GetDigit(index--); 16634514f5e3Sopenharmony_ci remainDigitBits = BigInt::DATEBITS; 16644514f5e3Sopenharmony_ci } 16654514f5e3Sopenharmony_ci uint32_t temp = 1ULL << (remainDigitBits - 1); 16664514f5e3Sopenharmony_ci if (!(digit & temp)) { 16674514f5e3Sopenharmony_ci return CalculateNumber(sign, mantissa, exponent); 16684514f5e3Sopenharmony_ci } 16694514f5e3Sopenharmony_ci if ((digit & (temp - 1)) != 0) { 16704514f5e3Sopenharmony_ci return Rounding(sign, mantissa, exponent, true); 16714514f5e3Sopenharmony_ci } 16724514f5e3Sopenharmony_ci while (index > 0) { 16734514f5e3Sopenharmony_ci if (bigint->GetDigit(--index) != 0) { 16744514f5e3Sopenharmony_ci return Rounding(sign, mantissa, exponent, true); 16754514f5e3Sopenharmony_ci } 16764514f5e3Sopenharmony_ci } 16774514f5e3Sopenharmony_ci return Rounding(sign, mantissa, exponent, false); 16784514f5e3Sopenharmony_ci} 16794514f5e3Sopenharmony_ci 16804514f5e3Sopenharmony_cistatic int CompareToBitsLen(JSHandle<BigInt> bigint, int numBitLen, int &leadingZeros) 16814514f5e3Sopenharmony_ci{ 16824514f5e3Sopenharmony_ci uint32_t bigintLen = bigint->GetLength(); 16834514f5e3Sopenharmony_ci ASSERT(bigintLen > 0); 16844514f5e3Sopenharmony_ci uint32_t BigintHead = bigint->GetDigit(bigintLen - 1); 16854514f5e3Sopenharmony_ci leadingZeros = static_cast<int>(base::CountLeadingZeros(BigintHead)); 16864514f5e3Sopenharmony_ci int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS) - leadingZeros; 16874514f5e3Sopenharmony_ci bool bigintSign = bigint->GetSign(); 16884514f5e3Sopenharmony_ci if (bigintBitLen > numBitLen) { 16894514f5e3Sopenharmony_ci return bigintSign ? 0 : 1; 16904514f5e3Sopenharmony_ci } 16914514f5e3Sopenharmony_ci 16924514f5e3Sopenharmony_ci if (bigintBitLen < numBitLen) { 16934514f5e3Sopenharmony_ci return bigintSign ? 1 : 0; 16944514f5e3Sopenharmony_ci } 16954514f5e3Sopenharmony_ci return -1; 16964514f5e3Sopenharmony_ci} 16974514f5e3Sopenharmony_ci 16984514f5e3Sopenharmony_ciComparisonResult BigInt::CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number) 16994514f5e3Sopenharmony_ci{ 17004514f5e3Sopenharmony_ci double num = number->GetNumber(); 17014514f5e3Sopenharmony_ci bool numberSign = num < 0; 17024514f5e3Sopenharmony_ci if (std::isnan(num)) { 17034514f5e3Sopenharmony_ci return ComparisonResult::UNDEFINED; 17044514f5e3Sopenharmony_ci } 17054514f5e3Sopenharmony_ci if (!std::isfinite(num)) { 17064514f5e3Sopenharmony_ci return (!numberSign ? ComparisonResult::LESS : ComparisonResult::GREAT); 17074514f5e3Sopenharmony_ci } 17084514f5e3Sopenharmony_ci // Bit operations must be of integer type 17094514f5e3Sopenharmony_ci uint64_t bits = 0; 17104514f5e3Sopenharmony_ci if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) { 17114514f5e3Sopenharmony_ci LOG_FULL(FATAL) << "memcpy_s failed"; 17124514f5e3Sopenharmony_ci UNREACHABLE(); 17134514f5e3Sopenharmony_ci } 17144514f5e3Sopenharmony_ci int exponential = (bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF; 17154514f5e3Sopenharmony_ci 17164514f5e3Sopenharmony_ci // Take out bits 62-52 (11 bits in total) and subtract 1023 17174514f5e3Sopenharmony_ci int integerDigits = exponential - base::DOUBLE_EXPONENT_BIAS; 17184514f5e3Sopenharmony_ci uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT; 17194514f5e3Sopenharmony_ci bool bigintSign = bigint->GetSign(); 17204514f5e3Sopenharmony_ci // Handling the opposite sign 17214514f5e3Sopenharmony_ci if (!numberSign && bigintSign) { 17224514f5e3Sopenharmony_ci return ComparisonResult::LESS; 17234514f5e3Sopenharmony_ci } else if (numberSign && !bigintSign) { 17244514f5e3Sopenharmony_ci return ComparisonResult::GREAT; 17254514f5e3Sopenharmony_ci } 17264514f5e3Sopenharmony_ci if (bigint->IsZero() && !num) { 17274514f5e3Sopenharmony_ci return ComparisonResult::EQUAL; 17284514f5e3Sopenharmony_ci } 17294514f5e3Sopenharmony_ci if (bigint->IsZero() && num > 0) { 17304514f5e3Sopenharmony_ci return ComparisonResult::LESS; 17314514f5e3Sopenharmony_ci } 17324514f5e3Sopenharmony_ci 17334514f5e3Sopenharmony_ci if (integerDigits < 0) { 17344514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT; 17354514f5e3Sopenharmony_ci } 17364514f5e3Sopenharmony_ci 17374514f5e3Sopenharmony_ci // Compare the significant bits of bigint with the significant integer bits of double 17384514f5e3Sopenharmony_ci int leadingZeros = 0; 17394514f5e3Sopenharmony_ci int res = CompareToBitsLen(bigint, integerDigits + 1, leadingZeros); 17404514f5e3Sopenharmony_ci if (res == 0) { 17414514f5e3Sopenharmony_ci return ComparisonResult::LESS; 17424514f5e3Sopenharmony_ci } else if (res == 1) { 17434514f5e3Sopenharmony_ci return ComparisonResult::GREAT; 17444514f5e3Sopenharmony_ci } 17454514f5e3Sopenharmony_ci int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; // mantissaSize 17464514f5e3Sopenharmony_ci uint32_t bigintLen = bigint->GetLength(); 17474514f5e3Sopenharmony_ci int leftover = 0; 17484514f5e3Sopenharmony_ci bool IsFirstInto = true; 17494514f5e3Sopenharmony_ci ASSERT(bigintLen > 0); 17504514f5e3Sopenharmony_ci for (int index = static_cast<int>(bigintLen - 1); index >= 0; --index) { 17514514f5e3Sopenharmony_ci uint32_t doubleNum = 0; 17524514f5e3Sopenharmony_ci uint32_t BigintNum = bigint->GetDigit(index); 17534514f5e3Sopenharmony_ci if (IsFirstInto) { 17544514f5e3Sopenharmony_ci IsFirstInto = false; 17554514f5e3Sopenharmony_ci leftover = mantissaSize - BigInt::DATEBITS + leadingZeros + 1; 17564514f5e3Sopenharmony_ci doubleNum = static_cast<uint32_t>(mantissa >> leftover); 17574514f5e3Sopenharmony_ci mantissa = mantissa << (64 - leftover); // 64 : double bits 17584514f5e3Sopenharmony_ci if (BigintNum > doubleNum) { 17594514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT; 17604514f5e3Sopenharmony_ci } 17614514f5e3Sopenharmony_ci if (BigintNum < doubleNum) { 17624514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS; 17634514f5e3Sopenharmony_ci } 17644514f5e3Sopenharmony_ci } else { 17654514f5e3Sopenharmony_ci leftover -= BigInt::DATEBITS; 17664514f5e3Sopenharmony_ci doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS); 17674514f5e3Sopenharmony_ci mantissa = mantissa << BigInt::DATEBITS; 17684514f5e3Sopenharmony_ci if (BigintNum > doubleNum) { 17694514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT; 17704514f5e3Sopenharmony_ci } 17714514f5e3Sopenharmony_ci if (BigintNum < doubleNum) { 17724514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS; 17734514f5e3Sopenharmony_ci } 17744514f5e3Sopenharmony_ci leftover -= BigInt::DATEBITS; 17754514f5e3Sopenharmony_ci } 17764514f5e3Sopenharmony_ci } 17774514f5e3Sopenharmony_ci 17784514f5e3Sopenharmony_ci if (mantissa != 0) { 17794514f5e3Sopenharmony_ci ASSERT(leftover > 0); 17804514f5e3Sopenharmony_ci return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS; 17814514f5e3Sopenharmony_ci } 17824514f5e3Sopenharmony_ci return ComparisonResult::EQUAL; 17834514f5e3Sopenharmony_ci} 17844514f5e3Sopenharmony_ci} // namespace 1785