2022-03-10 13:25:06 +00:00
|
|
|
|
/*
|
|
|
|
|
* Copyright (c) 2022 Huawei Device Co., Ltd.
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
#include "ecmascript/js_bigint.h"
|
2022-07-23 10:33:33 +00:00
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
#include "ecmascript/base/bit_helper.h"
|
2022-06-28 08:24:24 +00:00
|
|
|
|
#include "ecmascript/js_tagged_value-inl.h"
|
|
|
|
|
#include "ecmascript/js_tagged_number.h"
|
|
|
|
|
|
2022-03-10 13:25:06 +00:00
|
|
|
|
namespace panda::ecmascript {
|
|
|
|
|
class ObjectFactory;
|
|
|
|
|
constexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
2022-03-21 01:43:26 +00:00
|
|
|
|
static int CharToInt(char c)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-05-20 07:22:39 +00:00
|
|
|
|
uint32_t res = 0;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (c >= '0' && c <= '9') {
|
|
|
|
|
res = c - '0';
|
|
|
|
|
} else if (c >= 'A' && c <= 'Z') {
|
|
|
|
|
res = c - 'A' + 10; // 10:res must Greater than 10.
|
|
|
|
|
} else if (c >= 'a' && c <= 'z') {
|
|
|
|
|
res = c - 'a' + 10; // 10:res must Greater than 10
|
|
|
|
|
}
|
2022-05-20 07:22:39 +00:00
|
|
|
|
return static_cast<int>(res);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
static void Division(CString &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
|
|
|
|
ASSERT(conversionToRadix != 0);
|
2022-03-21 03:38:21 +00:00
|
|
|
|
uint32_t temp = 0;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
remain = 0;
|
|
|
|
|
for (size_t i = 0; i < num.size(); i++) {
|
2022-04-12 08:49:37 +00:00
|
|
|
|
temp = (currentRadix * remain + static_cast<uint32_t>(CharToInt(num[i])));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
num[i] = dp[temp / conversionToRadix];
|
|
|
|
|
remain = temp % conversionToRadix;
|
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
size_t count = 0;
|
|
|
|
|
while (count < num.size() && num[count] == '0') {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
count++;
|
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
num = num.substr(count);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString BigIntHelper::Conversion(const CString &num, uint32_t conversionToRadix, uint32_t currentRadix)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
|
|
|
|
ASSERT(conversionToRadix != 0);
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString newNum = num;
|
|
|
|
|
CString res;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
uint32_t remain = 0;
|
|
|
|
|
while (newNum.size() != 0) {
|
2022-06-13 02:36:44 +00:00
|
|
|
|
Division(newNum, conversionToRadix, currentRadix, remain);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
res = dp[remain] + res;
|
|
|
|
|
}
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
2022-09-02 08:31:33 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::GetUint64MaxBigint(JSThread *thread)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, 3);
|
|
|
|
|
bigint->SetDigit(0, 0);
|
|
|
|
|
bigint->SetDigit(1, 0);
|
|
|
|
|
bigint->SetDigit(2, 1);
|
|
|
|
|
return bigint;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::GetInt64MaxBigint(JSThread *thread)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, 2);
|
|
|
|
|
bigint->SetDigit(0, 0);
|
|
|
|
|
bigint->SetDigit(1, 0x80000000); // 0x80000000:Int MAX
|
|
|
|
|
return bigint;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
JSHandle<BigInt> BigIntHelper::SetBigInt(JSThread *thread, const CString &numStr, uint32_t currentRadix)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
|
|
|
|
int flag = 0;
|
|
|
|
|
if (numStr[0] == '-') {
|
|
|
|
|
flag = 1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString binaryStr = "";
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (currentRadix != BigInt::BINARY) {
|
|
|
|
|
binaryStr = Conversion(numStr.substr(flag), BigInt::BINARY, currentRadix);
|
|
|
|
|
} else {
|
|
|
|
|
binaryStr = numStr.substr(flag);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> bigint;
|
|
|
|
|
size_t binaryStrLen = binaryStr.size();
|
|
|
|
|
size_t len = binaryStrLen / BigInt::DATEBITS;
|
|
|
|
|
size_t mod = binaryStrLen % BigInt::DATEBITS;
|
|
|
|
|
int index = 0;
|
|
|
|
|
if (mod == 0) {
|
2022-04-15 06:42:30 +00:00
|
|
|
|
index = static_cast<int>(len - 1);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigint = BigInt::CreateBigint(thread, len);
|
|
|
|
|
} else {
|
|
|
|
|
len++;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
index = static_cast<int>(len - 1);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigint = BigInt::CreateBigint(thread, len);
|
|
|
|
|
uint32_t val = 0;
|
|
|
|
|
for (size_t i = 0; i < mod; ++i) {
|
|
|
|
|
val <<= 1;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
val |= static_cast<uint32_t>(binaryStr[i] - '0');
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(index, val);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
index--;
|
|
|
|
|
}
|
|
|
|
|
if (flag == 1) {
|
|
|
|
|
bigint->SetSign(true);
|
|
|
|
|
}
|
|
|
|
|
size_t i = mod;
|
|
|
|
|
while (i < binaryStrLen) {
|
|
|
|
|
uint32_t val = 0;
|
|
|
|
|
for (size_t j = 0; j < BigInt::DATEBITS && i < binaryStrLen; ++j, ++i) {
|
|
|
|
|
val <<= 1;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
val |= static_cast<uint32_t>(binaryStr[i] - '0');
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(index, val);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
index--;
|
|
|
|
|
}
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigIntHelper::RightTruncate(JSThread *thread, JSHandle<BigInt> x)
|
|
|
|
|
{
|
2022-04-12 08:49:37 +00:00
|
|
|
|
int len = static_cast<int>(x->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
ASSERT(len != 0);
|
|
|
|
|
if (len == 1 && x->GetDigit(0) == 0) {
|
|
|
|
|
x->SetSign(false);
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
int index = len - 1;
|
|
|
|
|
if (x->GetDigit(index) != 0) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
while (index >= 0) {
|
|
|
|
|
if (x->GetDigit(index) != 0) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
index--;
|
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (index == -1) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
return BigInt::Int32ToBigInt(thread, 0);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
} else {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
ASSERT(index >= 0);
|
|
|
|
|
return BigInt::Copy(thread, x, index + 1);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString BigIntHelper::GetBinary(const BigInt *bigint)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(bigint != nullptr);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
int index = 0;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
int len = static_cast<int>(bigint->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
int strLen = BigInt::DATEBITS * len;
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString res(strLen, '0');
|
2022-03-10 13:25:06 +00:00
|
|
|
|
int strIndex = strLen - 1;
|
|
|
|
|
while (index < len) {
|
|
|
|
|
int bityLen = BigInt::DATEBITS;
|
|
|
|
|
uint32_t val = bigint->GetDigit(index);
|
|
|
|
|
while (bityLen--) {
|
|
|
|
|
res[strIndex--] = (val & 1) + '0';
|
|
|
|
|
val = val >> 1;
|
|
|
|
|
}
|
|
|
|
|
index++;
|
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
DeZero(res);
|
|
|
|
|
return res;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-28 08:24:24 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::CreateBigint(JSThread *thread, uint32_t length)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-06-28 08:24:24 +00:00
|
|
|
|
ASSERT(length < MAXSIZE);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
2022-06-28 08:24:24 +00:00
|
|
|
|
JSHandle<BigInt> bigint = factory->NewBigInt(length);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return bigint;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// 6.1.6.2.13
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bool BigInt::Equal(const JSTaggedValue &x, const JSTaggedValue &y)
|
|
|
|
|
{
|
|
|
|
|
BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
|
|
|
|
|
BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
|
|
|
|
|
return Equal(xVal, yVal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BigInt::Equal(const BigInt *x, const BigInt *y)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(x != nullptr);
|
|
|
|
|
ASSERT(y != nullptr);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (x->GetSign() != y->GetSign() || x->GetLength() != y->GetLength()) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
for (uint32_t i = 0; i < x->GetLength(); ++i) {
|
|
|
|
|
if (x->GetDigit(i) != y->GetDigit(i)) {
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// 6.1.6.2.14
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bool BigInt::SameValue(const JSTaggedValue &x, const JSTaggedValue &y)
|
|
|
|
|
{
|
|
|
|
|
return Equal(x, y);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// 6.1.6.2.15
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bool BigInt::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y)
|
|
|
|
|
{
|
|
|
|
|
return Equal(x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseOp(JSThread *thread, Operate op, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
uint32_t maxLen = 0;
|
|
|
|
|
uint32_t minLen = 0;
|
|
|
|
|
uint32_t xlen = x->GetLength();
|
|
|
|
|
uint32_t ylen = y->GetLength();
|
|
|
|
|
if (xlen > ylen) {
|
|
|
|
|
maxLen = xlen;
|
|
|
|
|
minLen = ylen;
|
|
|
|
|
} else {
|
|
|
|
|
maxLen = ylen;
|
|
|
|
|
minLen = xlen;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, maxLen);
|
|
|
|
|
for (size_t i = 0; i < minLen; ++i) {
|
|
|
|
|
if (op == Operate::OR) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, x->GetDigit(i) | y->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
} else if (op == Operate::AND) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, x->GetDigit(i) & y->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
} else {
|
|
|
|
|
ASSERT(op == Operate::XOR);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, x->GetDigit(i) ^ y->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (op == Operate::OR || op == Operate::XOR) {
|
|
|
|
|
if (xlen > ylen) {
|
|
|
|
|
for (size_t i = ylen; i < xlen; ++i) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, x->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
} else if (ylen > xlen) {
|
|
|
|
|
for (size_t i = xlen; i < ylen; ++i) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, y->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> OneIsNegativeAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
uint32_t xLength = x->GetLength();
|
|
|
|
|
uint32_t yLength = yVal->GetLength();
|
|
|
|
|
uint32_t minLen = xLength;
|
|
|
|
|
if (xLength > yLength) {
|
|
|
|
|
minLen = yLength;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, xLength);
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
while (i < minLen) {
|
|
|
|
|
uint32_t res = x->GetDigit(i) & ~(yVal->GetDigit(i));
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, res);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
while (i < xLength) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, x->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, newBigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.1.6.2.20 BigInt::bitwiseAND ( x, y )
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (x->GetSign() && y->GetSign()) {
|
|
|
|
|
// (-x) & (-y) == -(((x-1) | (y-1)) + 1)
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength());
|
|
|
|
|
JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> temp = BitwiseOp(thread, Operate::OR, xVal, yVal);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> res = BitwiseAddOne(thread, temp);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
if (x->GetSign() != y->GetSign()) {
|
|
|
|
|
// x & (-y) == x & ~(y-1)
|
|
|
|
|
if (!x->GetSign()) {
|
|
|
|
|
return OneIsNegativeAND(thread, x, y);
|
|
|
|
|
} else {
|
|
|
|
|
return OneIsNegativeAND(thread, y, x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BitwiseOp(thread, Operate::AND, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> OneIsNegativeXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, y->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.1.6.2.21 BigInt::bitwiseOR ( x, y )
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseXOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (x->GetSign() && y->GetSign()) {
|
|
|
|
|
// (-x) ^ (-y) == (x-1) ^ (y-1)
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, x->GetLength());
|
|
|
|
|
JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, y->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return BitwiseOp(thread, Operate::XOR, xVal, yVal);
|
|
|
|
|
}
|
|
|
|
|
if (x->GetSign() != y->GetSign()) {
|
|
|
|
|
// x ^ (-y) == -((x ^ (y-1)) + 1)
|
|
|
|
|
if (!x->GetSign()) {
|
|
|
|
|
return OneIsNegativeXOR(thread, x, y);
|
|
|
|
|
} else {
|
|
|
|
|
return OneIsNegativeXOR(thread, y, x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BitwiseOp(thread, Operate::XOR, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseSubOne(JSThread *thread, JSHandle<BigInt> bigint, uint32_t maxLen)
|
|
|
|
|
{
|
|
|
|
|
ASSERT(!bigint->IsZero());
|
|
|
|
|
ASSERT(maxLen >= bigint->GetLength());
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, maxLen);
|
|
|
|
|
|
|
|
|
|
uint32_t bigintLen = bigint->GetLength();
|
|
|
|
|
uint32_t carry = 1;
|
|
|
|
|
for (uint32_t i = 0; i < bigintLen; i++) {
|
|
|
|
|
uint32_t bigintCarry = 0;
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, BigIntHelper::SubHelper(bigint->GetDigit(i), carry, bigintCarry));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
carry = bigintCarry;
|
|
|
|
|
}
|
|
|
|
|
ASSERT(!carry);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, newBigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseAddOne(JSThread *thread, JSHandle<BigInt> bigint)
|
|
|
|
|
{
|
|
|
|
|
uint32_t bigintLength = bigint->GetLength();
|
|
|
|
|
|
|
|
|
|
bool needExpend = true;
|
|
|
|
|
for (uint32_t i = 0; i < bigintLength; i++) {
|
|
|
|
|
if (std::numeric_limits<uint32_t>::max() != bigint->GetDigit(i)) {
|
|
|
|
|
needExpend = false;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
uint32_t newLength = bigintLength;
|
|
|
|
|
if (needExpend) {
|
|
|
|
|
newLength += 1;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, newLength);
|
|
|
|
|
|
|
|
|
|
uint32_t carry = 1;
|
|
|
|
|
for (uint32_t i = 0; i < bigintLength; i++) {
|
|
|
|
|
uint32_t bigintCarry = 0;
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, BigIntHelper::AddHelper(bigint->GetDigit(i), carry, bigintCarry));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
carry = bigintCarry;
|
|
|
|
|
}
|
|
|
|
|
if (needExpend) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(bigintLength, carry);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
newBigint->SetSign(true);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, newBigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> OneIsNegativeOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
uint32_t xLength = x->GetLength();
|
|
|
|
|
uint32_t maxLen = xLength;
|
|
|
|
|
if (maxLen < y->GetLength()) {
|
|
|
|
|
maxLen = y->GetLength();
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> yVal = BigInt::BitwiseSubOne(thread, y, maxLen);
|
|
|
|
|
uint32_t yLength = yVal->GetLength();
|
|
|
|
|
uint32_t minLen = xLength;
|
|
|
|
|
if (minLen > yLength) {
|
|
|
|
|
minLen = yLength;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> newBigint = BigInt::CreateBigint(thread, yLength);
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
while (i < minLen) {
|
|
|
|
|
uint32_t res = ~(x->GetDigit(i)) & yVal->GetDigit(i);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, res);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
while (i < yLength) {
|
2022-06-28 08:24:24 +00:00
|
|
|
|
newBigint->SetDigit(i, yVal->GetDigit(i));
|
2022-03-10 13:25:06 +00:00
|
|
|
|
++i;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> temp = BigIntHelper::RightTruncate(thread, newBigint);
|
|
|
|
|
JSHandle<BigInt> res = BigInt::BitwiseAddOne(thread, temp);
|
|
|
|
|
res->SetSign(true);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 6.1.6.2.22 BigInt::bitwiseOR ( x, y )
|
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseOR(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (x->GetSign() && y->GetSign()) {
|
|
|
|
|
// (-x) | (-y) == -(((x-1) & (y-1)) + 1)
|
|
|
|
|
uint32_t maxLen = x->GetLength();
|
|
|
|
|
uint32_t yLen = y->GetLength();
|
|
|
|
|
maxLen < yLen ? maxLen = yLen : 0;
|
|
|
|
|
JSHandle<BigInt> xVal = BitwiseSubOne(thread, x, maxLen);
|
|
|
|
|
JSHandle<BigInt> yVal = BitwiseSubOne(thread, y, yLen);
|
|
|
|
|
JSHandle<BigInt> temp = BitwiseOp(thread, Operate::AND, xVal, yVal);
|
|
|
|
|
JSHandle<BigInt> res = BitwiseAddOne(thread, temp);
|
|
|
|
|
res->SetSign(true);
|
|
|
|
|
return res;
|
|
|
|
|
}
|
|
|
|
|
if (x->GetSign() != y->GetSign()) {
|
|
|
|
|
// x | (-y) == -(((y-1) & ~x) + 1)
|
|
|
|
|
if (!x->GetSign()) {
|
|
|
|
|
return OneIsNegativeOR(thread, x, y);
|
|
|
|
|
} else {
|
|
|
|
|
return OneIsNegativeOR(thread, y, x);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BitwiseOp(thread, Operate::OR, x, y);
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// 6.1.6.2.23 BigInt::toString ( x )
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<EcmaString> BigInt::ToString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
|
|
|
|
|
{
|
|
|
|
|
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString result = bigint->ToStdString(conversionToRadix);
|
2022-04-09 02:34:11 +00:00
|
|
|
|
return factory->NewFromASCII(result.c_str());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString BigInt::ToStdString(uint32_t conversionToRadix) const
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-06-13 02:36:44 +00:00
|
|
|
|
CString result =
|
2022-03-21 01:43:26 +00:00
|
|
|
|
BigIntHelper::Conversion(BigIntHelper::GetBinary(this), conversionToRadix, BINARY);
|
|
|
|
|
if (GetSign()) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
result = "-" + result;
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSTaggedValue BigInt::NumberToBigInt(JSThread *thread, JSHandle<JSTaggedValue> number)
|
|
|
|
|
{
|
|
|
|
|
if (!number->IsInteger()) {
|
|
|
|
|
THROW_RANGE_ERROR_AND_RETURN(thread, "The number cannot be converted to a BigInt because it is not an integer",
|
|
|
|
|
JSTaggedValue::Exception());
|
|
|
|
|
}
|
|
|
|
|
double num = number->GetNumber();
|
|
|
|
|
if (num == 0.0) {
|
|
|
|
|
return Int32ToBigInt(thread, 0).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Bit operations must be of integer type
|
|
|
|
|
uint64_t bits = 0;
|
2022-03-21 01:43:26 +00:00
|
|
|
|
if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
|
2022-07-06 06:12:54 +00:00
|
|
|
|
LOG_FULL(FATAL) << "memcpy_s failed";
|
2022-03-21 01:43:26 +00:00
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
// Take out bits 62-52 (11 bits in total) and subtract 1023
|
2022-03-21 01:43:26 +00:00
|
|
|
|
uint64_t integerDigits = ((bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF) - base::DOUBLE_EXPONENT_BIAS;
|
2022-06-27 12:28:31 +00:00
|
|
|
|
uint32_t mayNeedLen = integerDigits / DATEBITS + 1;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
|
2022-06-27 12:28:31 +00:00
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, mayNeedLen);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigint->SetSign(num < 0);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT;
|
|
|
|
|
int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
|
|
|
|
|
int leftover = 0;
|
2022-06-27 12:28:31 +00:00
|
|
|
|
bool isFirstInto = true;
|
|
|
|
|
for (int index = static_cast<int>(mayNeedLen - 1); index >= 0; --index) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
uint32_t doubleNum = 0;
|
2022-06-27 12:28:31 +00:00
|
|
|
|
if (isFirstInto) {
|
|
|
|
|
isFirstInto = false;
|
|
|
|
|
leftover = mantissaSize - static_cast<int>(integerDigits % DATEBITS);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
doubleNum = static_cast<uint32_t>(mantissa >> leftover);
|
|
|
|
|
mantissa = mantissa << (64 - leftover); // 64 : double bits size
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(index, doubleNum);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
} else {
|
2022-06-27 12:28:31 +00:00
|
|
|
|
leftover -= DATEBITS;
|
|
|
|
|
doubleNum = static_cast<uint32_t>(mantissa >> DATEBITS);
|
|
|
|
|
mantissa = mantissa << DATEBITS;
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(index, doubleNum);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Int32ToBigInt(JSThread *thread, const int &number)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, 1);
|
|
|
|
|
uint32_t value = 0;
|
|
|
|
|
bool sign = number < 0;
|
|
|
|
|
if (sign) {
|
|
|
|
|
value = static_cast<uint32_t>(-(number + 1)) + 1;
|
|
|
|
|
} else {
|
|
|
|
|
value = number;
|
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(0, value);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
bigint->SetSign(sign);
|
|
|
|
|
return bigint;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::Uint32ToBigInt(JSThread *thread, const uint32_t &number)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, 1);
|
|
|
|
|
bigint->SetDigit(0, number);
|
|
|
|
|
return bigint;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
uint64_t value = 0;
|
|
|
|
|
bool sign = number < 0;
|
|
|
|
|
if (sign) {
|
|
|
|
|
value = static_cast<uint64_t>(-(number + 1)) + 1;
|
|
|
|
|
} else {
|
|
|
|
|
value = number;
|
|
|
|
|
}
|
2022-06-27 12:28:31 +00:00
|
|
|
|
JSHandle<BigInt> bigint = Uint64ToBigInt(thread, value);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
bigint->SetSign(sign);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, 2); // 2 : one int64_t bits need two uint32_t bits
|
2022-06-27 12:28:31 +00:00
|
|
|
|
uint32_t lowBits = static_cast<uint32_t>(number & 0xffffffff);
|
|
|
|
|
uint32_t highBits = static_cast<uint32_t>((number >> DATEBITS) & 0xffffffff);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(0, lowBits);
|
|
|
|
|
bigint->SetDigit(1, highBits);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-27 12:28:31 +00:00
|
|
|
|
uint64_t BigInt::ToUint64()
|
2022-06-13 02:36:44 +00:00
|
|
|
|
{
|
2022-06-13 11:59:21 +00:00
|
|
|
|
uint32_t len = GetLength();
|
2022-06-21 06:16:34 +00:00
|
|
|
|
ASSERT(len <= 2); // The maximum length of the BigInt data is less or equal 2
|
2022-06-27 12:28:31 +00:00
|
|
|
|
uint32_t lowBits = GetDigit(0);
|
|
|
|
|
uint32_t highBits = 0;
|
|
|
|
|
if (len > 1) {
|
|
|
|
|
highBits = GetDigit(1);
|
2022-06-13 02:36:44 +00:00
|
|
|
|
}
|
2022-06-27 12:28:31 +00:00
|
|
|
|
uint64_t value = static_cast<uint64_t>(lowBits);
|
|
|
|
|
value |= static_cast<uint64_t>(highBits) << DATEBITS;
|
2022-06-13 02:36:44 +00:00
|
|
|
|
if (GetSign()) {
|
|
|
|
|
value = ~(value - 1);
|
|
|
|
|
}
|
2022-06-27 12:28:31 +00:00
|
|
|
|
return value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int64_t BigInt::ToInt64()
|
|
|
|
|
{
|
|
|
|
|
return static_cast<int64_t>(ToUint64());
|
2022-06-13 02:36:44 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-10 13:25:06 +00:00
|
|
|
|
void BigInt::BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(cValue != nullptr);
|
|
|
|
|
ASSERT(lossless != nullptr);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint));
|
2022-04-07 09:33:59 +00:00
|
|
|
|
RETURN_IF_ABRUPT_COMPLETION(thread);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (Equal(bigInt64.GetTaggedValue(), bigint.GetTaggedValue())) {
|
|
|
|
|
*lossless = true;
|
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
*cValue = bigInt64->ToInt64();
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BigInt::BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(cValue != nullptr);
|
|
|
|
|
ASSERT(lossless != nullptr);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigint));
|
2022-04-07 09:33:59 +00:00
|
|
|
|
RETURN_IF_ABRUPT_COMPLETION(thread);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (Equal(bigUint64.GetTaggedValue(), bigint.GetTaggedValue())) {
|
|
|
|
|
*lossless = true;
|
|
|
|
|
}
|
2022-06-27 12:28:31 +00:00
|
|
|
|
*cValue = bigUint64->ToUint64();
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t *words)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(words != nullptr);
|
2022-06-27 12:28:31 +00:00
|
|
|
|
const uint32_t MULTIPLE = 2;
|
|
|
|
|
uint32_t needLen = size * MULTIPLE;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
|
2022-06-27 12:28:31 +00:00
|
|
|
|
for (uint32_t index = 0; index < size; ++index) {
|
|
|
|
|
uint32_t lowBits = static_cast<uint32_t>(words[index] & 0xffffffff);
|
|
|
|
|
uint32_t highBits = static_cast<uint32_t>((words[index] >> DATEBITS) & 0xffffffff);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(MULTIPLE * index, lowBits);
|
|
|
|
|
bigint->SetDigit(MULTIPLE * index + 1, highBits);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
bigint->SetSign(sign);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Add(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
bool xSignFlag = x->GetSign();
|
|
|
|
|
bool ySignFlag = y->GetSign();
|
|
|
|
|
// x + y == x + y
|
|
|
|
|
// -x + -y == -(x + y)
|
|
|
|
|
if (xSignFlag == ySignFlag) {
|
|
|
|
|
return BigintAdd(thread, x, y, xSignFlag);
|
|
|
|
|
}
|
|
|
|
|
// x + -y == x - y == -(y - x)
|
|
|
|
|
// -x + y == y - x == -(x - y)
|
|
|
|
|
uint32_t xLength = x->GetLength();
|
|
|
|
|
uint32_t yLength = y->GetLength();
|
2022-10-25 13:17:23 +00:00
|
|
|
|
int i = static_cast<int>(xLength) - 1;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
int subSize = static_cast<int>(xLength - yLength);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (subSize > 0) {
|
|
|
|
|
return BigintSub(thread, x, y, xSignFlag);
|
|
|
|
|
} else if (subSize == 0) {
|
|
|
|
|
while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
if ((x->GetDigit(i) > y->GetDigit(i))) {
|
|
|
|
|
return BigintSub(thread, x, y, xSignFlag);
|
|
|
|
|
} else {
|
|
|
|
|
return BigintSub(thread, y, x, ySignFlag);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return BigintSub(thread, y, x, ySignFlag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> BigInt::Subtract(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
bool xSignFlag = x->GetSign();
|
|
|
|
|
bool ySignFlag = y->GetSign();
|
|
|
|
|
if (xSignFlag != ySignFlag) {
|
|
|
|
|
// x - (-y) == x + y
|
|
|
|
|
// (-x) - y == -(x + y)
|
|
|
|
|
return BigintAdd(thread, x, y, xSignFlag);
|
|
|
|
|
}
|
|
|
|
|
// x - y == -(y - x)
|
|
|
|
|
// (-x) - (-y) == y - x == -(x - y)
|
|
|
|
|
uint32_t xLength = x->GetLength();
|
|
|
|
|
uint32_t yLength = y->GetLength();
|
|
|
|
|
uint32_t i = xLength - 1;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
int subSize = static_cast<int>(xLength - yLength);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (subSize > 0) {
|
|
|
|
|
return BigintSub(thread, x, y, xSignFlag);
|
|
|
|
|
} else if (subSize == 0) {
|
|
|
|
|
while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
|
|
|
|
|
i--;
|
|
|
|
|
}
|
|
|
|
|
if ((x->GetDigit(i) > y->GetDigit(i))) {
|
|
|
|
|
return BigintSub(thread, x, y, xSignFlag);
|
|
|
|
|
} else {
|
|
|
|
|
return BigintSub(thread, y, x, !ySignFlag);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
return BigintSub(thread, y, x, !ySignFlag);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BigintAdd(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
|
|
|
|
|
{
|
|
|
|
|
if (x->GetLength() < y->GetLength()) {
|
|
|
|
|
return BigintAdd(thread, y, x, resultSign);
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength() + 1);
|
|
|
|
|
uint32_t bigintCarry = 0;
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
while (i < y->GetLength()) {
|
|
|
|
|
uint32_t newBigintCarry = 0;
|
|
|
|
|
uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
|
|
|
|
|
addPlus = BigIntHelper::AddHelper(addPlus, bigintCarry, newBigintCarry);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, addPlus);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigintCarry = newBigintCarry;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
while (i < x->GetLength()) {
|
|
|
|
|
uint32_t newBigintCarry = 0;
|
|
|
|
|
uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, addPlus);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigintCarry = newBigintCarry;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, bigintCarry);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigint->SetSign(resultSign);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline uint32_t BigIntHelper::AddHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
|
|
|
|
|
{
|
|
|
|
|
uint32_t addPlus = x + y;
|
|
|
|
|
if (addPlus < x) {
|
|
|
|
|
bigintCarry += 1;
|
|
|
|
|
}
|
|
|
|
|
return addPlus;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BigintSub(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y, bool resultSign)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, x->GetLength());
|
|
|
|
|
uint32_t bigintCarry = 0;
|
|
|
|
|
uint32_t i = 0;
|
|
|
|
|
while (i < y->GetLength()) {
|
|
|
|
|
uint32_t newBigintCarry = 0;
|
|
|
|
|
uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), y->GetDigit(i), newBigintCarry);
|
|
|
|
|
minuSub = BigIntHelper::SubHelper(minuSub, bigintCarry, newBigintCarry);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, minuSub);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigintCarry = newBigintCarry;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
while (i < x->GetLength()) {
|
|
|
|
|
uint32_t newBigintCarry = 0;
|
|
|
|
|
uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
|
2022-06-28 08:24:24 +00:00
|
|
|
|
bigint->SetDigit(i, minuSub);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bigintCarry = newBigintCarry;
|
|
|
|
|
i++;
|
|
|
|
|
}
|
|
|
|
|
bigint->SetSign(resultSign);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BigintAddOne(JSThread *thread, JSHandle<BigInt> x)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
|
|
|
|
|
return Add(thread, x, temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::BigintSubOne(JSThread *thread, JSHandle<BigInt> x)
|
|
|
|
|
{
|
|
|
|
|
JSHandle<BigInt> temp = Int32ToBigInt(thread, 1);
|
|
|
|
|
return Subtract(thread, x, temp);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline uint32_t BigIntHelper::SubHelper(uint32_t x, uint32_t y, uint32_t &bigintCarry)
|
|
|
|
|
{
|
|
|
|
|
uint32_t minuSub = x - y;
|
|
|
|
|
if (minuSub > x) {
|
|
|
|
|
bigintCarry += 1;
|
|
|
|
|
}
|
|
|
|
|
return minuSub;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 07:04:57 +00:00
|
|
|
|
ComparisonResult BigInt::Compare(const JSTaggedValue &x, const JSTaggedValue &y)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
|
|
|
|
|
BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
|
|
|
|
|
return Compare(xVal, yVal);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ComparisonResult BigInt::Compare(const BigInt *x, const BigInt *y)
|
|
|
|
|
{
|
|
|
|
|
bool xSign = x->GetSign();
|
|
|
|
|
bool ySign = y->GetSign();
|
|
|
|
|
if (xSign != ySign) {
|
|
|
|
|
return xSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
|
|
|
|
|
}
|
|
|
|
|
ComparisonResult compar = AbsolutelyCompare(x, y);
|
|
|
|
|
if (xSign && compar != ComparisonResult::EQUAL) {
|
|
|
|
|
return compar == ComparisonResult::LESS ? ComparisonResult::GREAT : ComparisonResult::LESS;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return compar;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BigInt::LessThan(const JSTaggedValue &x, const JSTaggedValue &y)
|
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return Compare(x, y) == ComparisonResult::LESS;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
bool BigInt::LessThan(const BigInt *x, const BigInt *y)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
ASSERT(x != nullptr);
|
|
|
|
|
ASSERT(y != nullptr);
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return Compare(x, y) == ComparisonResult::LESS;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::SignedRightShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
bool xIsNull = x->GetDigit(0);
|
|
|
|
|
bool yIsNull = y->GetDigit(0);
|
|
|
|
|
if (!xIsNull || !yIsNull) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
if (y->GetSign()) {
|
|
|
|
|
return LeftShiftHelper(thread, x, y);
|
|
|
|
|
} else {
|
|
|
|
|
return RightShiftHelper(thread, x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-14 06:49:07 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::ReturnIfRightShiftOverMax(JSThread *thread, bool sign)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-14 06:49:07 +00:00
|
|
|
|
if (sign) {
|
|
|
|
|
return Int32ToBigInt(thread, -1);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
return Int32ToBigInt(thread, 0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BigInt::RightShift(JSHandle<BigInt> bigint, JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove)
|
|
|
|
|
{
|
|
|
|
|
uint32_t size = x->GetLength();
|
|
|
|
|
if (bitsMove == 0) {
|
|
|
|
|
for (uint32_t i = digitMove; i < size; i++) {
|
|
|
|
|
bigint->SetDigit(i - digitMove, x->GetDigit(i));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t carry = x->GetDigit(digitMove) >> bitsMove;
|
|
|
|
|
uint32_t last = size - digitMove - 1;
|
|
|
|
|
for (uint32_t i = 0; i < last; i++) {
|
|
|
|
|
uint32_t value = x->GetDigit(i + digitMove + 1);
|
|
|
|
|
bigint->SetDigit(i, (value << (DATEBITS - bitsMove)) | carry);
|
|
|
|
|
carry = value >> bitsMove;
|
|
|
|
|
}
|
|
|
|
|
bigint->SetDigit(last, carry);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BigInt::JudgeRoundDown(JSHandle<BigInt> x, uint32_t digitMove, uint32_t bitsMove, uint32_t &needLen,
|
|
|
|
|
bool &roundDown)
|
|
|
|
|
{
|
|
|
|
|
uint32_t stamp = (static_cast<uint32_t>(1U) << bitsMove) - 1;
|
|
|
|
|
if (x->GetDigit(digitMove) & stamp) {
|
|
|
|
|
roundDown = true;
|
|
|
|
|
} else {
|
|
|
|
|
for (uint32_t i = 0; i < digitMove; i++) {
|
|
|
|
|
if (x->GetDigit(i) != 0) {
|
|
|
|
|
roundDown = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
|
|
|
|
|
if (roundDown && bitsMove == 0) {
|
|
|
|
|
uint32_t highBits = x->GetDigit(x->GetLength() - 1);
|
|
|
|
|
// If all the most significant bits are 1, we think that carry will cause overflow,
|
|
|
|
|
// and needLen needs to be increased by 1
|
|
|
|
|
if ((~highBits) == 0) {
|
|
|
|
|
needLen++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
bool sign = x->GetSign();
|
|
|
|
|
if (y->GetLength() > 1 || y->GetDigit(0) > MAXBITS) {
|
|
|
|
|
return ReturnIfRightShiftOverMax(thread, sign);
|
|
|
|
|
}
|
|
|
|
|
uint32_t moveNum = y->GetDigit(0);
|
|
|
|
|
uint32_t digitMove = moveNum / DATEBITS;
|
|
|
|
|
uint32_t bitsMove = moveNum % DATEBITS;
|
|
|
|
|
if (x->GetLength() <= digitMove) {
|
|
|
|
|
return ReturnIfRightShiftOverMax(thread, sign);
|
|
|
|
|
}
|
|
|
|
|
uint32_t needLen = x->GetLength() - digitMove;
|
|
|
|
|
bool roundDown = false;
|
|
|
|
|
if (sign) {
|
|
|
|
|
// If it is a negative number, you need to consider whether it will carry after moving.
|
|
|
|
|
// NeedLen may need to increase by 1
|
|
|
|
|
JudgeRoundDown(x, digitMove, bitsMove, needLen, roundDown);
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
|
|
|
|
|
|
|
|
|
|
RightShift(bigint, x, digitMove, bitsMove);
|
|
|
|
|
bigint = BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
if (sign) {
|
|
|
|
|
bigint->SetSign(true);
|
|
|
|
|
if (roundDown) {
|
|
|
|
|
return BitwiseAddOne(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return bigint;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::LeftShift(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (y->GetSign()) {
|
|
|
|
|
return RightShiftHelper(thread, x, y);
|
|
|
|
|
} else {
|
|
|
|
|
return LeftShiftHelper(thread, x, y);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::LeftShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
2022-10-14 06:49:07 +00:00
|
|
|
|
ASSERT(y->GetLength() == 1);
|
|
|
|
|
ASSERT(y->GetDigit(0) <= MAXBITS);
|
|
|
|
|
uint32_t moveNum = y->GetDigit(0);
|
|
|
|
|
uint32_t digitMove = moveNum / DATEBITS;
|
|
|
|
|
uint32_t bitsMove = moveNum % DATEBITS;
|
|
|
|
|
// If bitsMove is not zero, needLen needs to be increased by 1
|
|
|
|
|
uint32_t needLen = digitMove + x->GetLength() + static_cast<uint32_t>(!!bitsMove);
|
|
|
|
|
ASSERT(needLen < MAXSIZE);
|
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
|
|
|
|
|
if (bitsMove == 0) {
|
|
|
|
|
uint32_t index = digitMove;
|
|
|
|
|
while (index < needLen) {
|
|
|
|
|
bigint->SetDigit(index, x->GetDigit(index - digitMove));
|
|
|
|
|
++index;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t index = 0;
|
|
|
|
|
while (index < x->GetLength()) {
|
|
|
|
|
uint32_t value = x->GetDigit(index);
|
|
|
|
|
bigint->SetDigit(index + digitMove, (value << bitsMove) | carry);
|
|
|
|
|
carry = value >> (DATEBITS - bitsMove);
|
|
|
|
|
++index;
|
|
|
|
|
}
|
|
|
|
|
if (carry != 0) {
|
|
|
|
|
ASSERT(index + digitMove < needLen);
|
|
|
|
|
bigint->SetDigit(index + digitMove, carry);
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
bigint->SetSign(x->GetSign());
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSTaggedValue BigInt::UnsignedRightShift(JSThread *thread)
|
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
THROW_TYPE_ERROR_AND_RETURN(thread, "BigInt have no unsigned right shift, use >> instead",
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSTaggedValue::Exception());
|
|
|
|
|
}
|
|
|
|
|
|
2022-06-28 08:24:24 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::Copy(JSThread *thread, JSHandle<BigInt> x, uint32_t len)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-06-28 08:24:24 +00:00
|
|
|
|
ASSERT(x->GetLength() >= len);
|
|
|
|
|
JSHandle<BigInt> newBig = CreateBigint(thread, len);
|
|
|
|
|
std::copy(x->GetData(), x->GetData() + len, newBig->GetData());
|
|
|
|
|
newBig->SetSign(x->GetSign());
|
|
|
|
|
return newBig;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::UnaryMinus(JSThread *thread, JSHandle<BigInt> x)
|
|
|
|
|
{
|
|
|
|
|
if (x->IsZero()) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
2022-06-28 08:24:24 +00:00
|
|
|
|
JSHandle<BigInt> y = Copy(thread, x, x->GetLength());
|
2022-03-10 13:25:06 +00:00
|
|
|
|
y->SetSign(!y->GetSign());
|
|
|
|
|
return y;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// 6.1.6.2.2 BigInt::bitwiseNOT ( x )
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::BitwiseNOT(JSThread *thread, JSHandle<BigInt> x)
|
|
|
|
|
{
|
|
|
|
|
// ~(-x) == ~(~(x-1)) == x-1
|
|
|
|
|
// ~x == -x-1 == -(x+1)
|
|
|
|
|
JSHandle<BigInt> result = BigintAddOne(thread, x);
|
|
|
|
|
if (x->GetSign()) {
|
|
|
|
|
result->SetSign(false);
|
|
|
|
|
} else {
|
|
|
|
|
result->SetSign(true);
|
|
|
|
|
}
|
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Exponentiate(JSThread *thread, JSHandle<BigInt> base, JSHandle<BigInt> exponent)
|
|
|
|
|
{
|
|
|
|
|
if (exponent->GetSign()) {
|
|
|
|
|
JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
|
|
|
|
|
THROW_RANGE_ERROR_AND_RETURN(thread, "Exponent must be positive", bigint);
|
|
|
|
|
}
|
|
|
|
|
ASSERT(exponent->GetLength() == 1);
|
|
|
|
|
if (exponent->IsZero()) {
|
2022-10-14 06:49:07 +00:00
|
|
|
|
return Int32ToBigInt(thread, 1);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
uint32_t expValue = exponent->GetDigit(0);
|
|
|
|
|
if (base->IsZero() || expValue == 1) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return base;
|
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
if (base->GetLength() == 1 && base->GetDigit(0) == 1) {
|
|
|
|
|
if (base->GetSign() && !(expValue & 1)) {
|
|
|
|
|
return BigInt::UnaryMinus(thread, base);
|
|
|
|
|
}
|
|
|
|
|
return base;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
if (base->GetLength() == 1 && base->GetDigit(0) == 2) { // 2 : We use fast path processing 2 ^ n
|
2022-10-21 03:45:49 +00:00
|
|
|
|
uint32_t needLength = expValue / DATEBITS + 1;
|
2022-10-14 06:49:07 +00:00
|
|
|
|
JSHandle<BigInt> bigint = CreateBigint(thread, needLength);
|
|
|
|
|
uint32_t value = 1U << (expValue % DATEBITS);
|
|
|
|
|
bigint->SetDigit(needLength - 1, value);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (base->GetSign()) {
|
2022-10-14 06:49:07 +00:00
|
|
|
|
bigint->SetSign(static_cast<bool>(expValue & 1));
|
|
|
|
|
}
|
|
|
|
|
return bigint;
|
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
JSMutableHandle<BigInt> result(thread, JSTaggedValue::Null());
|
2022-10-14 06:49:07 +00:00
|
|
|
|
JSMutableHandle<BigInt> temp(thread, base);
|
|
|
|
|
if (expValue & 1) {
|
|
|
|
|
result.Update(base);
|
|
|
|
|
}
|
|
|
|
|
expValue >>= 1;
|
|
|
|
|
for (; expValue; expValue >>= 1) {
|
|
|
|
|
temp.Update(BigInt::Multiply(thread, temp, temp));
|
|
|
|
|
if (expValue & 1) {
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (result.GetTaggedValue().IsNull()) {
|
2022-10-14 06:49:07 +00:00
|
|
|
|
result.Update(temp);
|
|
|
|
|
} else {
|
|
|
|
|
result.Update(BigInt::Multiply(thread, result, temp));
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
ASSERT(result.GetTaggedValue().IsBigInt());
|
|
|
|
|
return result;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
|
2022-10-14 06:49:07 +00:00
|
|
|
|
std::tuple<uint32_t, uint32_t> BigInt::Mul(uint32_t x, uint32_t y)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-14 06:49:07 +00:00
|
|
|
|
uint32_t lowBitX = x & HALFDATEMASK;
|
|
|
|
|
uint32_t highBitX = x >> HALFDATEBITS;
|
|
|
|
|
uint32_t lowBitY = y & HALFDATEMASK;
|
|
|
|
|
uint32_t highBitY = y >> HALFDATEBITS;
|
|
|
|
|
// {highBitX lowBitX} * {highBitY lowBitY}
|
|
|
|
|
uint32_t lowRes = lowBitX * lowBitY;
|
|
|
|
|
uint32_t highRes = highBitX * highBitY;
|
|
|
|
|
uint32_t midRes1 = lowBitX * highBitY;
|
|
|
|
|
uint32_t midRes2 = highBitX * lowBitY;
|
|
|
|
|
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t low = BigIntHelper::AddHelper(
|
|
|
|
|
BigIntHelper::AddHelper(lowRes, midRes1 << HALFDATEBITS, carry), midRes2 << HALFDATEBITS, carry);
|
|
|
|
|
uint32_t high = (midRes1 >> HALFDATEBITS) + (midRes2 >> HALFDATEBITS) + highRes + carry;
|
|
|
|
|
|
|
|
|
|
return std::make_tuple(high, low);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (x->IsZero()) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
if (y->IsZero()) {
|
|
|
|
|
return y;
|
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
uint32_t needLength = x->GetLength() + y->GetLength();
|
|
|
|
|
JSHandle<BigInt> bigint = BigInt::CreateBigint(thread, needLength);
|
2022-06-13 02:36:44 +00:00
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
// the algorithm here is similar to the way we use paper money to calculate multiplication.
|
|
|
|
|
// Generally, we first calculate the partial product, and then add up to get the result.
|
|
|
|
|
// The only difference here is that multiplication and addition are calculated synchronously
|
2022-10-14 06:49:07 +00:00
|
|
|
|
for (uint32_t i = 0; i < x->GetLength(); i++) {
|
|
|
|
|
uint32_t xVal = x->GetDigit(i);
|
2022-10-25 13:17:23 +00:00
|
|
|
|
// If the current multiplier is 0, we will skip this round of calculation to improve performance.
|
|
|
|
|
// If we do not skip, the correctness of the calculation will not be affected
|
2022-10-14 06:49:07 +00:00
|
|
|
|
if (xVal == 0) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t high = 0;
|
|
|
|
|
uint32_t index = i;
|
|
|
|
|
for (uint32_t j = 0; j < y->GetLength(); j++) {
|
|
|
|
|
uint32_t currentCarry = 0;
|
|
|
|
|
uint32_t value = bigint->GetDigit(index);
|
|
|
|
|
value = BigIntHelper::AddHelper(value, high, currentCarry);
|
|
|
|
|
value = BigIntHelper::AddHelper(value, carry, currentCarry);
|
|
|
|
|
|
|
|
|
|
uint32_t low;
|
|
|
|
|
std::tie(high, low) = Mul(xVal, y->GetDigit(j));
|
|
|
|
|
value = BigIntHelper::AddHelper(value, low, currentCarry);
|
|
|
|
|
bigint->SetDigit(index, value);
|
|
|
|
|
carry = currentCarry;
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
while (carry != 0 || high != 0) {
|
|
|
|
|
ASSERT(index < bigint->GetLength());
|
|
|
|
|
uint32_t value = bigint->GetDigit(index);
|
|
|
|
|
uint32_t currentCarry = 0;
|
|
|
|
|
value = BigIntHelper::AddHelper(value, high, currentCarry);
|
|
|
|
|
high = 0;
|
|
|
|
|
value = BigIntHelper::AddHelper(value, carry, currentCarry);
|
|
|
|
|
bigint->SetDigit(index, value);
|
|
|
|
|
carry = currentCarry;
|
|
|
|
|
index++;
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-14 06:49:07 +00:00
|
|
|
|
|
|
|
|
|
bigint->SetSign(x->GetSign() != y->GetSign());
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, bigint);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-06-13 02:36:44 +00:00
|
|
|
|
void BigIntHelper::DeZero(CString &a)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-06-13 02:36:44 +00:00
|
|
|
|
size_t count = 0;
|
|
|
|
|
while (count < a.size() && a[count] == '0') {
|
|
|
|
|
count++;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-06-13 02:36:44 +00:00
|
|
|
|
if (count == a.size()) {
|
|
|
|
|
a = "0";
|
|
|
|
|
} else {
|
|
|
|
|
a = a.substr(count);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
ComparisonResult BigInt::AbsolutelyCompare(const BigInt *x, const BigInt *y)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
uint32_t xLen = x->GetLength();
|
|
|
|
|
uint32_t yLen = y->GetLength();
|
|
|
|
|
if (xLen > yLen) {
|
|
|
|
|
return ComparisonResult::GREAT;
|
|
|
|
|
} else if (xLen < yLen) {
|
|
|
|
|
return ComparisonResult::LESS;
|
|
|
|
|
} else {
|
|
|
|
|
int index = static_cast<int>(xLen) - 1;
|
|
|
|
|
for (; index >= 0; --index) {
|
|
|
|
|
if (x->GetDigit(index) != y->GetDigit(index)) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (index < 0) {
|
|
|
|
|
return ComparisonResult::EQUAL;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return x->GetDigit(index) > y->GetDigit(index) ? ComparisonResult::GREAT : ComparisonResult::LESS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t BigInt::DivideAndRemainder(uint32_t highBit, uint32_t lowBit, uint32_t divisor, uint32_t& remainder)
|
|
|
|
|
{
|
|
|
|
|
uint32_t leadingZeros = base::CountLeadingZeros(divisor);
|
|
|
|
|
// Before calculating, we need to align the operands to the left
|
|
|
|
|
divisor <<= leadingZeros;
|
|
|
|
|
uint32_t lowDividend = lowBit << leadingZeros;
|
|
|
|
|
uint32_t highDividend = highBit;
|
|
|
|
|
if (leadingZeros != 0) {
|
|
|
|
|
// highBit is the remainder of the last calculation, which must be less than or equal to the divisor,
|
|
|
|
|
// so high << leadingZeros will not lose the significant bit
|
|
|
|
|
highDividend = (highBit << leadingZeros) | (lowBit >> (DATEBITS - leadingZeros));
|
|
|
|
|
}
|
|
|
|
|
uint32_t highDivisor = divisor >> HALFDATEBITS;
|
|
|
|
|
uint32_t lowDivisor = divisor & HALFDATEMASK;
|
|
|
|
|
uint32_t lowDividend1 = lowDividend >> HALFDATEBITS;
|
|
|
|
|
uint32_t lowDividend2 = lowDividend & HALFDATEMASK;
|
|
|
|
|
uint32_t highQuotient = highDividend / highDivisor;
|
|
|
|
|
uint32_t tempRemainder = highDividend - highQuotient * highDivisor;
|
|
|
|
|
|
|
|
|
|
// Similar to the ordinary division calculation, here we use HALFUINT32VALUE as the carry unit
|
|
|
|
|
// Calculate high order results first
|
|
|
|
|
while (highQuotient >= HALFUINT32VALUE ||
|
|
|
|
|
highQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend1) {
|
|
|
|
|
highQuotient--;
|
|
|
|
|
tempRemainder += highDivisor;
|
|
|
|
|
if (tempRemainder >= HALFUINT32VALUE)
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
uint32_t tempLowDividend = highDividend * HALFUINT32VALUE + lowDividend1 - highQuotient * divisor;
|
|
|
|
|
uint32_t lowQuotient = tempLowDividend / highDivisor;
|
|
|
|
|
tempRemainder = tempLowDividend - lowQuotient * highDivisor;
|
|
|
|
|
|
|
|
|
|
// Then calculate the low order result
|
|
|
|
|
while (lowQuotient >= HALFUINT32VALUE ||
|
|
|
|
|
lowQuotient * lowDivisor > tempRemainder * HALFUINT32VALUE + lowDividend2) {
|
|
|
|
|
lowQuotient--;
|
|
|
|
|
tempRemainder += highDivisor;
|
|
|
|
|
if (tempRemainder >= HALFUINT32VALUE)
|
|
|
|
|
break;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
|
|
|
|
|
// In order to facilitate the calculation, we start to make left alignment
|
|
|
|
|
// At this time, we need to move right to get the correct remainder
|
|
|
|
|
remainder = (tempLowDividend * HALFUINT32VALUE + lowDividend2 - lowQuotient * divisor) >> leadingZeros;
|
|
|
|
|
return highQuotient * HALFUINT32VALUE + lowQuotient;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::FormatLeftShift(JSThread *thread, uint32_t shift, JSHandle<BigInt> bigint, bool neeedAddOne)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (!neeedAddOne && shift == 0) {
|
|
|
|
|
return bigint;
|
|
|
|
|
}
|
|
|
|
|
uint32_t len = bigint->GetLength();
|
|
|
|
|
uint32_t needLen = len;
|
|
|
|
|
if (neeedAddOne) {
|
|
|
|
|
needLen += 1;
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> result = CreateBigint(thread, needLen);
|
|
|
|
|
if (shift == 0) {
|
|
|
|
|
std::copy(bigint->GetData(), bigint->GetData() + len, result->GetData());
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t index = 0;
|
|
|
|
|
while (index < len) {
|
|
|
|
|
uint32_t value = bigint->GetDigit(index);
|
|
|
|
|
result->SetDigit(index, (value << shift) | carry);
|
|
|
|
|
carry = value >> (DATEBITS - shift);
|
|
|
|
|
index++;
|
|
|
|
|
}
|
|
|
|
|
if (carry != 0) {
|
|
|
|
|
ASSERT(neeedAddOne);
|
|
|
|
|
result->SetDigit(index, carry);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return result;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void BigInt::UnformattedRightShift(JSHandle<BigInt> bigint, uint32_t shift)
|
|
|
|
|
{
|
|
|
|
|
RightShift(bigint, bigint, 0, shift);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
bool BigInt::SpecialMultiplyAndSub(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t q, JSHandle<BigInt> qv,
|
|
|
|
|
uint32_t pos)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
uint32_t lastCarry = 0;
|
|
|
|
|
uint32_t lastHigh = 0;
|
|
|
|
|
uint32_t len = v->GetLength();
|
|
|
|
|
// Calculate multiplication first
|
|
|
|
|
for (uint32_t i = 0; i < len; ++i) {
|
|
|
|
|
uint32_t value = v->GetDigit(i);
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t high = 0;
|
|
|
|
|
std::tie(high, value) = Mul(value, q);
|
|
|
|
|
// The current value plus the high and carry of the last calculation
|
|
|
|
|
value = BigIntHelper::AddHelper(value, lastHigh, carry);
|
|
|
|
|
value = BigIntHelper::AddHelper(value, lastCarry, carry);
|
|
|
|
|
qv->SetDigit(i, value);
|
|
|
|
|
// Record the new high bit and carry for the next round
|
|
|
|
|
lastCarry = carry;
|
|
|
|
|
lastHigh = high;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
qv->SetDigit(len, lastHigh + lastCarry);
|
|
|
|
|
|
|
|
|
|
// Next, subtract
|
|
|
|
|
uint32_t lastBorrow = 0;
|
|
|
|
|
for (uint32_t i = 0; i < qv->GetLength(); ++i) {
|
|
|
|
|
uint32_t borrow = 0;
|
|
|
|
|
uint32_t value = BigIntHelper::SubHelper(u->GetDigit(pos + i), qv->GetDigit(i), borrow);
|
|
|
|
|
value = BigIntHelper::SubHelper(value, lastBorrow, borrow);
|
|
|
|
|
u->SetDigit(pos + i, value);
|
|
|
|
|
lastBorrow = borrow;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
|
|
|
|
|
return lastBorrow > 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t BigInt::SpecialAdd(JSHandle<BigInt> u, JSHandle<BigInt> v, uint32_t pos)
|
|
|
|
|
{
|
|
|
|
|
uint32_t lastCarry = 0;
|
|
|
|
|
for (uint32_t i = 0; i < v->GetLength(); ++i) {
|
|
|
|
|
uint32_t carry = 0;
|
|
|
|
|
uint32_t value = BigIntHelper::AddHelper(u->GetDigit(pos + i), v->GetDigit(i), carry);
|
|
|
|
|
value = BigIntHelper::AddHelper(value, lastCarry, carry);
|
|
|
|
|
u->SetDigit(pos + i, value);
|
|
|
|
|
lastCarry = carry;
|
|
|
|
|
}
|
|
|
|
|
return lastCarry;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
uint32_t BigInt::ImproveAccuracy(uint32_t vHighest, uint32_t vHighestNext, uint32_t UHighest,
|
|
|
|
|
uint32_t UHighestNext, uint32_t q)
|
|
|
|
|
{
|
|
|
|
|
uint32_t high = 0;
|
|
|
|
|
uint32_t low = 0;
|
|
|
|
|
std::tie(high, low) = Mul(q, vHighestNext);
|
|
|
|
|
while (high > UHighest || (high == UHighest && low > UHighestNext)) {
|
|
|
|
|
q--;
|
|
|
|
|
UHighest += vHighest;
|
|
|
|
|
// if r is less than the current base, continue the next round of inspection. Here,
|
|
|
|
|
// we confirm whether r is greater than the current base by judging whether r overflows
|
|
|
|
|
if (UHighest < vHighest) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
std::tie(high, low) = Mul(q, vHighestNext);
|
|
|
|
|
}
|
|
|
|
|
return q;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::DivideAndRemainderWithBigintDivisor(JSThread *thread, JSHandle<BigInt> dividend,
|
|
|
|
|
JSHandle<BigInt> divisor,
|
|
|
|
|
JSMutableHandle<BigInt> &remainder)
|
|
|
|
|
{
|
|
|
|
|
uint32_t divisorLen = divisor->GetLength();
|
|
|
|
|
// the length of the quota is the length of the dividend minus the divisor
|
|
|
|
|
uint32_t quotientLen = dividend->GetLength() - divisorLen;
|
|
|
|
|
JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
|
|
|
|
|
if (remainder.GetTaggedValue().IsNull()) {
|
|
|
|
|
quotient.Update(CreateBigint(thread, quotientLen + 1));
|
|
|
|
|
}
|
|
|
|
|
// format the divisor and dividend so that the highest order of the divisor is
|
|
|
|
|
// greater than or equal to half of uint32_t
|
|
|
|
|
uint32_t leadingZeros = base::CountLeadingZeros(divisor->GetDigit(divisorLen - 1));
|
|
|
|
|
JSHandle<BigInt> v = FormatLeftShift(thread, leadingZeros, divisor, false);
|
|
|
|
|
JSHandle<BigInt> u = FormatLeftShift(thread, leadingZeros, dividend, true);
|
|
|
|
|
// qv is used to store the result of quotient * divisor of each round
|
|
|
|
|
JSHandle<BigInt> qv = CreateBigint(thread, divisorLen + 1);
|
|
|
|
|
uint32_t vHighest = v->GetDigit(divisorLen - 1);
|
|
|
|
|
for (int i = quotientLen; i >= 0; --i) {
|
|
|
|
|
uint32_t currentUHighest = u->GetDigit(i + divisorLen);
|
|
|
|
|
uint32_t r = 0;
|
|
|
|
|
uint32_t q = DivideAndRemainder(currentUHighest, u->GetDigit(i + divisorLen - 1), vHighest, r);
|
|
|
|
|
// VHighest = currentUHighest means that q may be equal to the current base
|
|
|
|
|
// In the current program, the current base is the maximum value of uint32 plus 1
|
|
|
|
|
if (vHighest == currentUHighest) {
|
|
|
|
|
q = std::numeric_limits<uint32_t>::max();
|
|
|
|
|
} else {
|
|
|
|
|
uint32_t vHighestNext = v->GetDigit(divisorLen - 2); // 2 : Get the second most significant bit
|
|
|
|
|
uint32_t currentUHighestNext = u->GetDigit(i + divisorLen - 2); // 2 : ditto
|
|
|
|
|
|
|
|
|
|
// The following operations will make q only 1 greater than the value we want in most cases,
|
|
|
|
|
// and will not be less than it
|
|
|
|
|
q = ImproveAccuracy(vHighest, vHighestNext, r, currentUHighestNext, q);
|
|
|
|
|
}
|
|
|
|
|
// multiplication and subtraction
|
|
|
|
|
if (SpecialMultiplyAndSub(u, v, q, qv, i)) {
|
|
|
|
|
q--;
|
|
|
|
|
uint32_t carry = SpecialAdd(u, v, i);
|
|
|
|
|
u->SetDigit(i + divisorLen, u->GetDigit(i + divisorLen) + carry);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (remainder.GetTaggedValue().IsNull()) {
|
|
|
|
|
quotient->SetDigit(i, q);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
if (!remainder.GetTaggedValue().IsNull()) {
|
|
|
|
|
// at the beginning of this procedure, we performed the left shift operation.
|
|
|
|
|
// Here, we get the correct result by shifting the same number of digits to the right
|
|
|
|
|
UnformattedRightShift(u, leadingZeros);
|
|
|
|
|
remainder.Update(u);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
return quotient;
|
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::DivideAndRemainderWithUint32Divisor(JSThread *thread, JSHandle<BigInt> dividend,
|
|
|
|
|
uint32_t divisor, JSMutableHandle<BigInt> &remainder)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
uint32_t r = 0;
|
|
|
|
|
JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
|
|
|
|
|
if (!remainder.GetTaggedValue().IsNull()) {
|
|
|
|
|
for (int i = dividend->GetLength() - 1; i >= 0; --i) {
|
|
|
|
|
DivideAndRemainder(r, dividend->GetDigit(i), divisor, r);
|
|
|
|
|
remainder.Update(Uint32ToBigInt(thread, r));
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
quotient.Update(CreateBigint(thread, dividend->GetLength()));
|
|
|
|
|
for (int i = dividend->GetLength() - 1; i >= 0; --i) {
|
|
|
|
|
uint32_t q = DivideAndRemainder(r, dividend->GetDigit(i), divisor, r);
|
|
|
|
|
quotient->SetDigit(i, q);
|
|
|
|
|
}
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return quotient;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
// The algorithm here refers to algorithm D in Volume 2 of <The Art of Computer Programming>
|
2022-03-10 13:25:06 +00:00
|
|
|
|
JSHandle<BigInt> BigInt::Divide(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
|
|
|
|
{
|
|
|
|
|
if (y->IsZero()) {
|
|
|
|
|
JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
|
|
|
|
|
THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
|
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
// returns 0 if x is less than y
|
|
|
|
|
JSMutableHandle<BigInt> quotient(thread, JSTaggedValue::Null());
|
|
|
|
|
bool sign = x->GetSign() != y->GetSign();
|
|
|
|
|
ComparisonResult compare = AbsolutelyCompare(*x, *y);
|
|
|
|
|
if (compare == ComparisonResult::LESS) {
|
|
|
|
|
return Int32ToBigInt(thread, 0);
|
|
|
|
|
}
|
|
|
|
|
if (compare == ComparisonResult::EQUAL) {
|
|
|
|
|
quotient.Update(Int32ToBigInt(thread, 1));
|
|
|
|
|
quotient->SetSign(sign);
|
|
|
|
|
return quotient;
|
|
|
|
|
}
|
|
|
|
|
// if y is 1, return +x or -x
|
|
|
|
|
if (y->IsUint32() && y->GetDigit(0) == 1) {
|
|
|
|
|
if (sign == x->GetSign()) {
|
|
|
|
|
return x;
|
|
|
|
|
}
|
|
|
|
|
return UnaryMinus(thread, x);
|
|
|
|
|
}
|
|
|
|
|
JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Null());
|
|
|
|
|
if (y->IsUint32()) {
|
|
|
|
|
// When the divisor is uint32_t, we have a faster and simpler algorithm to calculate
|
|
|
|
|
quotient.Update(DivideAndRemainderWithUint32Divisor(thread, x, y->GetDigit(0), remainder));
|
|
|
|
|
} else {
|
|
|
|
|
ASSERT(y->GetLength() >= 1); // 1 : Entering the current branch length must be greater than 1
|
|
|
|
|
quotient.Update(DivideAndRemainderWithBigintDivisor(thread, x, y, remainder));
|
|
|
|
|
}
|
|
|
|
|
ASSERT(quotient.GetTaggedValue().IsBigInt());
|
|
|
|
|
quotient->SetSign(sign);
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, quotient);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::Remainder(JSThread *thread, JSHandle<BigInt> n, JSHandle<BigInt> d)
|
|
|
|
|
{
|
|
|
|
|
if (d->IsZero()) {
|
|
|
|
|
JSHandle<BigInt> bigint(thread, JSTaggedValue::Exception());
|
|
|
|
|
THROW_RANGE_ERROR_AND_RETURN(thread, "Division by zero", bigint);
|
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
ComparisonResult compare = AbsolutelyCompare(*n, *d);
|
|
|
|
|
if (n->IsZero() || compare == ComparisonResult::LESS) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return n;
|
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (compare == ComparisonResult::EQUAL || (d->IsUint32() && d->GetDigit(0) == 1)) {
|
|
|
|
|
return Int32ToBigInt(thread, 0);
|
|
|
|
|
}
|
|
|
|
|
JSMutableHandle<BigInt> remainder(thread, JSTaggedValue::Undefined());
|
|
|
|
|
if (d->IsUint32()) {
|
|
|
|
|
// When the divisor is uint32_t, we have a faster and simpler algorithm to calculate
|
|
|
|
|
DivideAndRemainderWithUint32Divisor(thread, n, d->GetDigit(0), remainder);
|
|
|
|
|
} else {
|
|
|
|
|
ASSERT(d->GetLength() > 1); // 1 : Entering the current branch length must be greater than 1
|
|
|
|
|
DivideAndRemainderWithBigintDivisor(thread, n, d, remainder);
|
|
|
|
|
}
|
|
|
|
|
ASSERT(remainder.GetTaggedValue().IsBigInt());
|
|
|
|
|
remainder->SetSign(n->GetSign());
|
|
|
|
|
return BigIntHelper::RightTruncate(thread, remainder);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSHandle<BigInt> BigInt::FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal)
|
|
|
|
|
{
|
2022-10-25 13:17:23 +00:00
|
|
|
|
JSHandle<BigInt> remainder = Remainder(thread, leftVal, rightVal);
|
|
|
|
|
if (leftVal->GetSign() && !remainder->IsZero()) {
|
|
|
|
|
return Add(thread, remainder, rightVal);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-10-25 13:17:23 +00:00
|
|
|
|
return remainder;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSTaggedValue BigInt::AsUintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
|
|
|
|
|
{
|
|
|
|
|
uint32_t bit = bits.ToUint32();
|
|
|
|
|
if (bit == 0) {
|
|
|
|
|
return Int32ToBigInt(thread, 0).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
if (bigint->IsZero()) {
|
|
|
|
|
return bigint.GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit);
|
|
|
|
|
JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
|
|
|
|
|
JSHandle<BigInt> tValue = Exponentiate(thread, base, exponent);
|
|
|
|
|
return FloorMod(thread, bigint, tValue).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSTaggedValue BigInt::AsintN(JSThread *thread, JSTaggedNumber &bits, JSHandle<BigInt> bigint)
|
|
|
|
|
{
|
|
|
|
|
uint32_t bit = bits.ToUint32();
|
|
|
|
|
if (bit == 0) {
|
|
|
|
|
return Int32ToBigInt(thread, 0).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
if (bigint->IsZero()) {
|
|
|
|
|
return bigint.GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
JSHandle<BigInt> exp = Int32ToBigInt(thread, bit);
|
|
|
|
|
JSHandle<BigInt> exponent = Int32ToBigInt(thread, bit - 1);
|
|
|
|
|
JSHandle<BigInt> base = Int32ToBigInt(thread, 2); // 2 : base value
|
|
|
|
|
JSHandle<BigInt> tValue = Exponentiate(thread, base, exp);
|
|
|
|
|
JSHandle<BigInt> modValue = FloorMod(thread, bigint, tValue);
|
|
|
|
|
JSHandle<BigInt> resValue = Exponentiate(thread, base, exponent);
|
|
|
|
|
// If mod ≥ 2bits - 1, return ℤ(mod - 2bits); otherwise, return (mod).
|
2022-10-25 13:17:23 +00:00
|
|
|
|
if (Compare(*resValue, *modValue) != ComparisonResult::GREAT) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
return Subtract(thread, modValue, tValue).GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
return modValue.GetTaggedValue();
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-21 01:43:26 +00:00
|
|
|
|
static JSTaggedNumber CalculateNumber(const uint64_t &sign, const uint64_t &mantissa, uint64_t &exponent)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
2022-03-21 01:43:26 +00:00
|
|
|
|
exponent = (exponent + base::DOUBLE_EXPONENT_BIAS) << base::DOUBLE_SIGNIFICAND_SIZE;
|
|
|
|
|
uint64_t doubleBit = sign | exponent | mantissa;
|
|
|
|
|
double res = 0;
|
|
|
|
|
if (memcpy_s(&res, sizeof(res), &doubleBit, sizeof(doubleBit)) != EOK) {
|
2022-07-06 06:12:54 +00:00
|
|
|
|
LOG_FULL(FATAL) << "memcpy_s failed";
|
2022-03-21 01:43:26 +00:00
|
|
|
|
UNREACHABLE();
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
2022-03-21 01:43:26 +00:00
|
|
|
|
return JSTaggedNumber(res);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static JSTaggedNumber Rounding(const uint64_t &sign, uint64_t &mantissa, uint64_t &exponent, bool needRound)
|
|
|
|
|
{
|
|
|
|
|
if (needRound || (mantissa & 1) == 1) {
|
|
|
|
|
++mantissa;
|
|
|
|
|
if ((mantissa >> base::DOUBLE_SIGNIFICAND_SIZE) != 0) {
|
|
|
|
|
mantissa = 0;
|
|
|
|
|
exponent++;
|
|
|
|
|
if (exponent > base::DOUBLE_EXPONENT_BIAS)
|
|
|
|
|
return JSTaggedNumber(sign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return CalculateNumber(sign, mantissa, exponent);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
JSTaggedNumber BigInt::BigIntToNumber(JSHandle<BigInt> bigint)
|
|
|
|
|
{
|
|
|
|
|
if (bigint->IsZero()) {
|
|
|
|
|
return JSTaggedNumber(0);
|
|
|
|
|
}
|
|
|
|
|
uint32_t bigintLen = bigint->GetLength();
|
|
|
|
|
uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
|
2022-10-25 13:17:23 +00:00
|
|
|
|
uint32_t leadingZeros = base::CountLeadingZeros(BigintHead);
|
|
|
|
|
int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS) - leadingZeros;
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// if Significant bits greater than 1024 then double is infinity
|
|
|
|
|
bool bigintSign = bigint->GetSign();
|
|
|
|
|
if (bigintBitLen > (base::DOUBLE_EXPONENT_BIAS + 1)) {
|
|
|
|
|
return JSTaggedNumber(bigintSign ? -base::POSITIVE_INFINITY : base::POSITIVE_INFINITY);
|
|
|
|
|
}
|
|
|
|
|
uint64_t sign = bigintSign ? 1ULL << 63 : 0; // 63 : Set the sign bit of sign to 1
|
2022-10-25 13:17:23 +00:00
|
|
|
|
int needMoveBit = leadingZeros + BigInt::DATEBITS + 1;
|
2022-03-21 01:43:26 +00:00
|
|
|
|
// Align to the most significant bit, then right shift 12 bits so that the head of the mantissa is in place
|
|
|
|
|
uint64_t mantissa = (static_cast<uint64_t>(BigintHead) << needMoveBit) >> 12; // 12 mantissa just has 52 bits
|
|
|
|
|
int remainMantissaBits = needMoveBit - 12;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
uint64_t exponent = static_cast<uint64_t>(bigintBitLen - 1);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
int index = static_cast<int>(bigintLen - 1);
|
|
|
|
|
uint32_t digit = 0;
|
|
|
|
|
if (index > 0) {
|
|
|
|
|
digit = bigint->GetDigit(--index);
|
|
|
|
|
} else {
|
|
|
|
|
return CalculateNumber(sign, mantissa, exponent);
|
|
|
|
|
}
|
|
|
|
|
// pad unset mantissa
|
2022-03-23 03:50:40 +00:00
|
|
|
|
if (static_cast<uint32_t>(remainMantissaBits) >= BigInt::DATEBITS) {
|
2022-03-21 01:43:26 +00:00
|
|
|
|
mantissa |= (static_cast<uint64_t>(digit) << (remainMantissaBits - BigInt::DATEBITS));
|
|
|
|
|
remainMantissaBits -= BigInt::DATEBITS;
|
|
|
|
|
index--;
|
|
|
|
|
}
|
|
|
|
|
if (remainMantissaBits > 0 && index >= 0) {
|
|
|
|
|
digit = bigint->GetDigit(index);
|
|
|
|
|
mantissa |= (static_cast<uint64_t>(digit) >> (BigInt::DATEBITS - remainMantissaBits));
|
|
|
|
|
remainMantissaBits -= BigInt::DATEBITS;
|
|
|
|
|
}
|
|
|
|
|
// After the mantissa is filled, if the bits of bigint have not been used up, consider the rounding problem
|
|
|
|
|
// The remaining bits of the current digit
|
2022-05-31 03:21:37 +00:00
|
|
|
|
if (remainMantissaBits > 0) {
|
|
|
|
|
return CalculateNumber(sign, mantissa, exponent);
|
|
|
|
|
}
|
2022-03-21 01:43:26 +00:00
|
|
|
|
int remainDigitBits = 0;
|
|
|
|
|
if (remainMantissaBits < 0) {
|
|
|
|
|
remainDigitBits = -remainMantissaBits;
|
2022-05-31 03:21:37 +00:00
|
|
|
|
} else {
|
2022-03-21 01:43:26 +00:00
|
|
|
|
if (!index) {
|
|
|
|
|
return CalculateNumber(sign, mantissa, exponent);
|
|
|
|
|
}
|
|
|
|
|
digit = bigint->GetDigit(index--);
|
|
|
|
|
remainDigitBits = BigInt::DATEBITS;
|
|
|
|
|
}
|
|
|
|
|
uint32_t temp = 1ULL << (remainDigitBits - 1);
|
|
|
|
|
if (!(digit & temp)) {
|
|
|
|
|
return CalculateNumber(sign, mantissa, exponent);
|
|
|
|
|
}
|
|
|
|
|
if ((digit & (temp - 1)) != 0) {
|
|
|
|
|
return Rounding(sign, mantissa, exponent, true);
|
|
|
|
|
}
|
|
|
|
|
while (index > 0) {
|
|
|
|
|
if (bigint->GetDigit(index--) != 0) {
|
|
|
|
|
return Rounding(sign, mantissa, exponent, true);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return Rounding(sign, mantissa, exponent, false);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
}
|
|
|
|
|
|
2022-10-25 13:17:23 +00:00
|
|
|
|
static int CompareToBitsLen(JSHandle<BigInt> bigint, int numBitLen, int &leadingZeros)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
|
|
|
|
uint32_t bigintLen = bigint->GetLength();
|
|
|
|
|
uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
|
2022-10-25 13:17:23 +00:00
|
|
|
|
leadingZeros = static_cast<int>(base::CountLeadingZeros(BigintHead));
|
|
|
|
|
int bigintBitLen = static_cast<int>(bigintLen * BigInt::DATEBITS) - leadingZeros;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bool bigintSign = bigint->GetSign();
|
|
|
|
|
if (bigintBitLen > numBitLen) {
|
|
|
|
|
return bigintSign ? 0 : 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (bigintBitLen < numBitLen) {
|
|
|
|
|
return bigintSign ? 1 : 0;
|
|
|
|
|
}
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
|
2022-03-24 07:04:57 +00:00
|
|
|
|
ComparisonResult BigInt::CompareWithNumber(JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number)
|
2022-03-10 13:25:06 +00:00
|
|
|
|
{
|
|
|
|
|
double num = number->GetNumber();
|
|
|
|
|
bool numberSign = num < 0;
|
|
|
|
|
if (std::isnan(num)) {
|
|
|
|
|
return ComparisonResult::UNDEFINED;
|
|
|
|
|
}
|
|
|
|
|
if (!std::isfinite(num)) {
|
|
|
|
|
return (!numberSign ? ComparisonResult::LESS : ComparisonResult::GREAT);
|
|
|
|
|
}
|
|
|
|
|
// Bit operations must be of integer type
|
|
|
|
|
uint64_t bits = 0;
|
2022-03-21 01:43:26 +00:00
|
|
|
|
if (memcpy_s(&bits, sizeof(bits), &num, sizeof(num)) != EOK) {
|
2022-07-06 06:12:54 +00:00
|
|
|
|
LOG_FULL(FATAL) << "memcpy_s failed";
|
2022-03-21 01:43:26 +00:00
|
|
|
|
UNREACHABLE();
|
|
|
|
|
}
|
|
|
|
|
int exponential = (bits >> base::DOUBLE_SIGNIFICAND_SIZE) & 0x7FF;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
|
|
|
|
|
// Take out bits 62-52 (11 bits in total) and subtract 1023
|
2022-03-21 01:43:26 +00:00
|
|
|
|
int integerDigits = exponential - base::DOUBLE_EXPONENT_BIAS;
|
|
|
|
|
uint64_t mantissa = (bits & base::DOUBLE_SIGNIFICAND_MASK) | base::DOUBLE_HIDDEN_BIT;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
bool bigintSign = bigint->GetSign();
|
|
|
|
|
// Handling the opposite sign
|
|
|
|
|
if (!numberSign && bigintSign) {
|
|
|
|
|
return ComparisonResult::LESS;
|
|
|
|
|
} else if (numberSign && !bigintSign) {
|
|
|
|
|
return ComparisonResult::GREAT;
|
|
|
|
|
}
|
|
|
|
|
if (bigint->IsZero() && !num) {
|
|
|
|
|
return ComparisonResult::EQUAL;
|
|
|
|
|
}
|
|
|
|
|
if (bigint->IsZero() && num > 0) {
|
|
|
|
|
return ComparisonResult::LESS;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (integerDigits < 0) {
|
|
|
|
|
return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Compare the significant bits of bigint with the significant integer bits of double
|
2022-10-25 13:17:23 +00:00
|
|
|
|
int leadingZeros = 0;
|
|
|
|
|
int res = CompareToBitsLen(bigint, integerDigits + 1, leadingZeros);
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (res == 0) {
|
|
|
|
|
return ComparisonResult::LESS;
|
|
|
|
|
} else if (res == 1) {
|
|
|
|
|
return ComparisonResult::GREAT;
|
|
|
|
|
}
|
2022-03-21 01:43:26 +00:00
|
|
|
|
int mantissaSize = base::DOUBLE_SIGNIFICAND_SIZE; // mantissaSize
|
2022-03-10 13:25:06 +00:00
|
|
|
|
uint32_t bigintLen = bigint->GetLength();
|
|
|
|
|
int leftover = 0;
|
|
|
|
|
bool IsFirstInto = true;
|
2022-04-12 08:49:37 +00:00
|
|
|
|
for (int index = static_cast<int>(bigintLen - 1); index >= 0; --index) {
|
2022-03-10 13:25:06 +00:00
|
|
|
|
uint32_t doubleNum = 0;
|
|
|
|
|
uint32_t BigintNum = bigint->GetDigit(index);
|
|
|
|
|
if (IsFirstInto) {
|
|
|
|
|
IsFirstInto = false;
|
2022-10-25 13:17:23 +00:00
|
|
|
|
leftover = mantissaSize - BigInt::DATEBITS + leadingZeros + 1;
|
2022-03-10 13:25:06 +00:00
|
|
|
|
doubleNum = static_cast<uint32_t>(mantissa >> leftover);
|
2022-03-21 01:43:26 +00:00
|
|
|
|
mantissa = mantissa << (64 - leftover); // 64 : double bits
|
2022-03-10 13:25:06 +00:00
|
|
|
|
if (BigintNum > doubleNum) {
|
|
|
|
|
return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
|
|
|
|
|
}
|
|
|
|
|
if (BigintNum < doubleNum) {
|
|
|
|
|
return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
leftover -= BigInt::DATEBITS;
|
|
|
|
|
doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS);
|
|
|
|
|
mantissa = mantissa << BigInt::DATEBITS;
|
|
|
|
|
if (BigintNum > doubleNum) {
|
|
|
|
|
return bigintSign ? ComparisonResult::LESS : ComparisonResult::GREAT;
|
|
|
|
|
}
|
|
|
|
|
if (BigintNum < doubleNum) {
|
|
|
|
|
return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
|
|
|
|
|
}
|
|
|
|
|
leftover -= BigInt::DATEBITS;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (mantissa != 0) {
|
|
|
|
|
ASSERT(leftover > 0);
|
|
|
|
|
return bigintSign ? ComparisonResult::GREAT : ComparisonResult::LESS;
|
|
|
|
|
}
|
|
|
|
|
return ComparisonResult::EQUAL;
|
|
|
|
|
}
|
2022-04-09 02:34:11 +00:00
|
|
|
|
} // namespace
|