mirror of
https://gitee.com/openharmony/arkcompiler_ets_runtime
synced 2024-10-07 16:13:49 +00:00
b744a006be
Signed-off-by: zhangyouyou <zhangyouyou2@huawei.com>
1342 lines
42 KiB
C++
1342 lines
42 KiB
C++
/*
|
||
* 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"
|
||
#include "ecmascript/base/number_helper.h"
|
||
#include "ecmascript/tagged_array-inl.h"
|
||
#include "object_factory.h"
|
||
#include "securec.h"
|
||
namespace panda::ecmascript {
|
||
class ObjectFactory;
|
||
constexpr char dp[] = "0123456789abcdefghijklmnopqrstuvwxyz";
|
||
int CharToInt(char c)
|
||
{
|
||
int res = 0;
|
||
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
|
||
}
|
||
return res;
|
||
}
|
||
|
||
std::string Division(std::string &num, uint32_t conversionToRadix, uint32_t currentRadix, uint32_t &remain)
|
||
{
|
||
ASSERT(conversionToRadix != 0);
|
||
int temp = 0;
|
||
remain = 0;
|
||
for (size_t i = 0; i < num.size(); i++) {
|
||
temp = (currentRadix * remain + CharToInt(num[i]));
|
||
num[i] = dp[temp / conversionToRadix];
|
||
remain = temp % conversionToRadix;
|
||
}
|
||
int count = 0;
|
||
while (num[count] == '0') {
|
||
count++;
|
||
}
|
||
return num.substr(count);
|
||
}
|
||
|
||
std::string BigIntHelper::Conversion(const std::string &num, uint32_t conversionToRadix, uint32_t currentRadix)
|
||
{
|
||
ASSERT(conversionToRadix != 0);
|
||
std::string newNum = num;
|
||
std::string res;
|
||
uint32_t remain = 0;
|
||
while (newNum.size() != 0) {
|
||
newNum = Division(newNum, conversionToRadix, currentRadix, remain);
|
||
res = dp[remain] + res;
|
||
}
|
||
return res;
|
||
}
|
||
|
||
JSHandle<BigInt> BigIntHelper::SetBigInt(JSThread *thread, const std::string &numStr, uint32_t currentRadix)
|
||
{
|
||
int flag = 0;
|
||
if (numStr[0] == '-') {
|
||
flag = 1;
|
||
}
|
||
|
||
std::string binaryStr = "";
|
||
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) {
|
||
index = len - 1;
|
||
bigint = BigInt::CreateBigint(thread, len);
|
||
} else {
|
||
len++;
|
||
index = len - 1;
|
||
bigint = BigInt::CreateBigint(thread, len);
|
||
uint32_t val = 0;
|
||
for (size_t i = 0; i < mod; ++i) {
|
||
val <<= 1;
|
||
val |= binaryStr[i] - '0';
|
||
}
|
||
BigInt::SetDigit(thread, bigint, index, val);
|
||
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;
|
||
val |= binaryStr[i] - '0';
|
||
}
|
||
BigInt::SetDigit(thread, bigint, index, val);
|
||
index--;
|
||
}
|
||
return BigIntHelper::RightTruncate(thread, bigint);
|
||
}
|
||
|
||
JSHandle<BigInt> BigIntHelper::RightTruncate(JSThread *thread, JSHandle<BigInt> x)
|
||
{
|
||
int len = x->GetLength();
|
||
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--;
|
||
}
|
||
JSHandle<TaggedArray> array(thread, x->GetData());
|
||
if (index == -1) {
|
||
array->Trim(thread, 1);
|
||
} else {
|
||
array->Trim(thread, index + 1);
|
||
}
|
||
if (x->IsZero()) {
|
||
x->SetSign(false);
|
||
}
|
||
return x;
|
||
}
|
||
|
||
std::string BigIntHelper::GetBinary(JSHandle<BigInt> bigint)
|
||
{
|
||
int index = 0;
|
||
int len = bigint->GetLength();
|
||
int strLen = BigInt::DATEBITS * len;
|
||
std::string res(strLen, '0');
|
||
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++;
|
||
}
|
||
size_t count = 0;
|
||
size_t resLen = res.size();
|
||
for (size_t i = 0; i < resLen; ++i) {
|
||
if (res[i] != '0') {
|
||
break;
|
||
}
|
||
count++;
|
||
}
|
||
if (count == resLen) {
|
||
return "0";
|
||
}
|
||
return res.substr(count);
|
||
}
|
||
|
||
uint32_t BigInt::GetDigit(uint32_t index) const
|
||
{
|
||
TaggedArray *TaggedArray = TaggedArray::Cast(GetData().GetTaggedObject());
|
||
JSTaggedValue digit = TaggedArray->Get(index);
|
||
return static_cast<uint32_t>(digit.GetInt());
|
||
}
|
||
|
||
void BigInt::SetDigit(JSThread* thread, JSHandle<BigInt> bigint, uint32_t index, uint32_t digit)
|
||
{
|
||
TaggedArray *TaggedArray = TaggedArray::Cast(bigint->GetData().GetTaggedObject());
|
||
TaggedArray->Set(thread, index, JSTaggedValue(static_cast<int32_t>(digit)));
|
||
}
|
||
|
||
uint32_t BigInt::GetLength() const
|
||
{
|
||
TaggedArray *TaggedArray = TaggedArray::Cast(GetData().GetTaggedObject());
|
||
return TaggedArray->GetLength();
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::CreateBigint(JSThread *thread, uint32_t size)
|
||
{
|
||
ASSERT(size < MAXSIZE);
|
||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||
JSHandle<BigInt> bigint = factory->NewBigInt();
|
||
JSHandle<TaggedArray> taggedArray = factory->NewTaggedArray(size);
|
||
bigint->SetData(thread, taggedArray.GetTaggedValue());
|
||
return bigint;
|
||
}
|
||
|
||
bool BigInt::Equal(const JSTaggedValue &x, const JSTaggedValue &y)
|
||
{
|
||
// 6.1.6.2.13
|
||
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)
|
||
{
|
||
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;
|
||
}
|
||
|
||
bool BigInt::SameValue(const JSTaggedValue &x, const JSTaggedValue &y)
|
||
{
|
||
// 6.1.6.2.14
|
||
return Equal(x, y);
|
||
}
|
||
|
||
bool BigInt::SameValueZero(const JSTaggedValue &x, const JSTaggedValue &y)
|
||
{
|
||
// 6.1.6.2.15
|
||
return Equal(x, y);
|
||
}
|
||
|
||
void BigInt::InitializationZero(JSThread *thread, JSHandle<BigInt> bigint)
|
||
{
|
||
uint32_t len = bigint->GetLength();
|
||
for (uint32_t i = 0; i < len; ++i) {
|
||
SetDigit(thread, bigint, i, 0);
|
||
}
|
||
}
|
||
|
||
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);
|
||
InitializationZero(thread, bigint);
|
||
for (size_t i = 0; i < minLen; ++i) {
|
||
if (op == Operate::OR) {
|
||
SetDigit(thread, bigint, i, x->GetDigit(i) | y->GetDigit(i));
|
||
} else if (op == Operate::AND) {
|
||
SetDigit(thread, bigint, i, x->GetDigit(i) & y->GetDigit(i));
|
||
} else {
|
||
ASSERT(op == Operate::XOR);
|
||
SetDigit(thread, bigint, i, x->GetDigit(i) ^ y->GetDigit(i));
|
||
}
|
||
}
|
||
if (op == Operate::OR || op == Operate::XOR) {
|
||
if (xlen > ylen) {
|
||
for (size_t i = ylen; i < xlen; ++i) {
|
||
SetDigit(thread, bigint, i, x->GetDigit(i));
|
||
}
|
||
} else if (ylen > xlen) {
|
||
for (size_t i = xlen; i < ylen; ++i) {
|
||
SetDigit(thread, bigint, i, y->GetDigit(i));
|
||
}
|
||
}
|
||
}
|
||
return BigIntHelper::RightTruncate(thread, bigint);
|
||
}
|
||
|
||
JSHandle<BigInt> OneIsNegativeAND(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
||
{
|
||
y->SetSign(false);
|
||
JSHandle<BigInt> yVal = BigInt::BigintSubOne(thread, y);
|
||
y->SetSign(true);
|
||
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));
|
||
BigInt::SetDigit(thread, newBigint, i, res);
|
||
++i;
|
||
}
|
||
while (i < xLength) {
|
||
BigInt::SetDigit(thread, newBigint, i, x->GetDigit(i));
|
||
++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)
|
||
x->SetSign(false);
|
||
y->SetSign(false);
|
||
JSHandle<BigInt> xVal = BigintSubOne(thread, x);
|
||
JSHandle<BigInt> yVal = BigintSubOne(thread, y);
|
||
x->SetSign(true);
|
||
y->SetSign(true);
|
||
JSHandle<BigInt> temp = BitwiseOp(thread, Operate::OR, xVal, yVal);
|
||
JSHandle<BigInt> res = BigintAddOne(thread, temp);
|
||
res->SetSign(true);
|
||
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)
|
||
{
|
||
y->SetSign(false);
|
||
JSHandle<BigInt> yVal = BigInt::BigintSubOne(thread, y);
|
||
y->SetSign(true);
|
||
JSHandle<BigInt> temp = BigInt::BitwiseOp(thread, Operate::XOR, x, yVal);
|
||
JSHandle<BigInt> res = BigInt::BigintAddOne(thread, temp);
|
||
res->SetSign(true);
|
||
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)
|
||
x->SetSign(false);
|
||
y->SetSign(false);
|
||
JSHandle<BigInt> xVal = BigintSubOne(thread, x);
|
||
JSHandle<BigInt> yVal = BigintSubOne(thread, y);
|
||
x->SetSign(true);
|
||
y->SetSign(true);
|
||
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;
|
||
BigInt::SetDigit(thread, newBigint, i, BigIntHelper::SubHelper(bigint->GetDigit(i), carry, bigintCarry));
|
||
carry = bigintCarry;
|
||
}
|
||
ASSERT(!carry);
|
||
for (uint32_t i = bigintLen; i < maxLen; i++) {
|
||
BigInt::SetDigit(thread, newBigint, i, 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;
|
||
BigInt::SetDigit(thread, newBigint, i, BigIntHelper::AddHelper(bigint->GetDigit(i), carry, bigintCarry));
|
||
carry = bigintCarry;
|
||
}
|
||
if (needExpend) {
|
||
BigInt::SetDigit(thread, newBigint, bigintLength, carry);
|
||
} else {
|
||
ASSERT(!carry);
|
||
}
|
||
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);
|
||
BigInt::SetDigit(thread, newBigint, i, res);
|
||
++i;
|
||
}
|
||
while (i < yLength) {
|
||
BigInt::SetDigit(thread, newBigint, i, yVal->GetDigit(i));
|
||
++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);
|
||
}
|
||
|
||
JSHandle<EcmaString> BigInt::ToString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
|
||
{
|
||
// 6.1.6.2.23 BigInt::toString ( x )
|
||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||
std::string result =
|
||
BigIntHelper::Conversion(BigIntHelper::GetBinary(bigint), conversionToRadix, BigInt::BINARY);
|
||
if (bigint->GetSign() && !(result.size() == 1 && result[0] == '0')) {
|
||
result = "-" + result;
|
||
}
|
||
return factory->NewFromStdStringUnCheck(result, true);
|
||
}
|
||
|
||
std::string BigInt::ToStdString(JSThread *thread, JSHandle<BigInt> bigint, uint32_t conversionToRadix)
|
||
{
|
||
std::string result =
|
||
BigIntHelper::Conversion(BigIntHelper::GetBinary(bigint), conversionToRadix, BigInt::BINARY);
|
||
if (bigint->GetSign() && !(result.size() == 1 && result[0] == '0')) {
|
||
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;
|
||
memcpy_s(&bits, sizeof(bits), &num, sizeof(num));
|
||
// Take out bits 62-52 (11 bits in total) and subtract 1023
|
||
uint64_t integerDigits = ((bits >> 52) & 0x7FF) - 0x3FF; // 52 : mantissa size
|
||
uint32_t MayNeedLen = integerDigits / BigInt::DATEBITS + 1;
|
||
|
||
JSHandle<BigInt> bigint = CreateBigint(thread, MayNeedLen);
|
||
bigint->SetSign(num < 0);
|
||
uint64_t mantissa = (bits & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
|
||
int mantissaSize = 52; // mantissaSize
|
||
|
||
int leftover = 0;
|
||
bool IsFirstInto = true;
|
||
for (int index = MayNeedLen - 1; index >= 0; --index) {
|
||
uint32_t doubleNum = 0;
|
||
if (IsFirstInto) {
|
||
IsFirstInto = false;
|
||
leftover = mantissaSize - (integerDigits % BigInt::DATEBITS);
|
||
doubleNum = static_cast<uint32_t>(mantissa >> leftover);
|
||
mantissa = mantissa << (64 - leftover); // 64 : double bits size
|
||
BigInt::SetDigit(thread, bigint, index, doubleNum);
|
||
} else {
|
||
leftover -= BigInt::DATEBITS;
|
||
doubleNum = static_cast<uint32_t>(mantissa >> BigInt::DATEBITS);
|
||
mantissa = mantissa << BigInt::DATEBITS;
|
||
BigInt::SetDigit(thread, bigint, index, doubleNum);
|
||
}
|
||
}
|
||
return BigIntHelper::RightTruncate(thread, bigint).GetTaggedValue();
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::Int32ToBigInt(JSThread *thread, const int &number)
|
||
{
|
||
return BigIntHelper::SetBigInt(thread, std::to_string(number));
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::Int64ToBigInt(JSThread *thread, const int64_t &number)
|
||
{
|
||
return BigIntHelper::SetBigInt(thread, std::to_string(number));
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::Uint64ToBigInt(JSThread *thread, const uint64_t &number)
|
||
{
|
||
return BigIntHelper::SetBigInt(thread, std::to_string(number));
|
||
}
|
||
|
||
void BigInt::BigIntToInt64(JSThread *thread, JSHandle<JSTaggedValue> bigint, int64_t *cValue, bool *lossless)
|
||
{
|
||
ASSERT(bigint->IsBigInt());
|
||
ASSERT(cValue);
|
||
ASSERT(lossless);
|
||
JSHandle<BigInt> bigInt64(thread, JSTaggedValue::ToBigInt64(thread, bigint));
|
||
if (Equal(bigInt64.GetTaggedValue(), bigint.GetTaggedValue())) {
|
||
*lossless = true;
|
||
}
|
||
uint32_t *addr = reinterpret_cast<uint32_t *>(cValue);
|
||
int len = bigInt64->GetLength();
|
||
for (int index = len - 1; index >= 0; --index) {
|
||
*(addr + index) = bigInt64->GetDigit(index);
|
||
}
|
||
if (bigInt64->GetSign()) {
|
||
*cValue = ~(*cValue - 1);
|
||
}
|
||
}
|
||
|
||
void BigInt::BigIntToUint64(JSThread *thread, JSHandle<JSTaggedValue> bigint, uint64_t *cValue, bool *lossless)
|
||
{
|
||
ASSERT(bigint->IsBigInt());
|
||
ASSERT(cValue);
|
||
ASSERT(lossless);
|
||
JSHandle<BigInt> bigUint64(thread, JSTaggedValue::ToBigUint64(thread, bigint));
|
||
if (Equal(bigUint64.GetTaggedValue(), bigint.GetTaggedValue())) {
|
||
*lossless = true;
|
||
}
|
||
uint32_t *addr = reinterpret_cast<uint32_t *>(cValue);
|
||
int len = bigUint64->GetLength();
|
||
for (int index = len - 1; index >= 0; --index) {
|
||
*(addr + index) = bigUint64->GetDigit(index);
|
||
}
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::CreateBigWords(JSThread *thread, bool sign, uint32_t size, const uint64_t* words)
|
||
{
|
||
uint32_t needLen = size * 2; // 2 : uint64_t size to uint32_t size
|
||
JSHandle<BigInt> bigint = CreateBigint(thread, needLen);
|
||
const uint32_t *digits = reinterpret_cast<const uint32_t *>(words);
|
||
for (uint32_t index = 0; index < needLen; ++index) {
|
||
SetDigit(thread, bigint, index, *(digits + index));
|
||
}
|
||
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();
|
||
uint32_t i = xLength - 1;
|
||
int subSize = xLength - yLength;
|
||
if (subSize > 0) {
|
||
return BigintSub(thread, x, y, xSignFlag);
|
||
} else if (subSize == 0) {
|
||
while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
|
||
i--;
|
||
}
|
||
if (i < 0) {
|
||
return BigintSub(thread, x, y, xSignFlag);
|
||
}
|
||
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;
|
||
int subSize = xLength - yLength;
|
||
if (subSize > 0) {
|
||
return BigintSub(thread, x, y, xSignFlag);
|
||
} else if (subSize == 0) {
|
||
while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
|
||
i--;
|
||
}
|
||
if (i < 0) {
|
||
return BigintSub(thread, x, y, xSignFlag);
|
||
}
|
||
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);
|
||
SetDigit(thread, bigint, i, addPlus);
|
||
bigintCarry = newBigintCarry;
|
||
i++;
|
||
}
|
||
while (i < x->GetLength()) {
|
||
uint32_t newBigintCarry = 0;
|
||
uint32_t addPlus = BigIntHelper::AddHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
|
||
SetDigit(thread, bigint, i, addPlus);
|
||
bigintCarry = newBigintCarry;
|
||
i++;
|
||
}
|
||
SetDigit(thread, bigint, i, bigintCarry);
|
||
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);
|
||
SetDigit(thread, bigint, i, minuSub);
|
||
bigintCarry = newBigintCarry;
|
||
i++;
|
||
}
|
||
while (i < x->GetLength()) {
|
||
uint32_t newBigintCarry = 0;
|
||
uint32_t minuSub = BigIntHelper::SubHelper(x->GetDigit(i), bigintCarry, newBigintCarry);
|
||
SetDigit(thread, bigint, i, minuSub);
|
||
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;
|
||
}
|
||
|
||
ComparisonResult BigInt::Compare(JSThread *thread, const JSTaggedValue &x, const JSTaggedValue &y)
|
||
{
|
||
if (!LessThan(x, y)) {
|
||
if (!LessThan(y, x)) {
|
||
return ComparisonResult::EQUAL;
|
||
}
|
||
return ComparisonResult::GREAT;
|
||
}
|
||
return ComparisonResult::LESS;
|
||
}
|
||
|
||
bool BigInt::LessThan(const JSTaggedValue &x, const JSTaggedValue &y)
|
||
{
|
||
BigInt* xVal = BigInt::Cast(x.GetTaggedObject());
|
||
BigInt* yVal = BigInt::Cast(y.GetTaggedObject());
|
||
return LessThan(xVal, yVal);
|
||
}
|
||
|
||
bool BigInt::LessThan(const BigInt *x, const BigInt *y)
|
||
{
|
||
bool xSignFlag = x->GetSign();
|
||
bool ySignFlag = y->GetSign();
|
||
int minSize = x->GetLength() - y->GetLength();
|
||
uint32_t i = x->GetLength() - 1;
|
||
if (xSignFlag != ySignFlag) {
|
||
return xSignFlag ? true : false;
|
||
} else {
|
||
if (minSize != 0 && xSignFlag) {
|
||
return minSize > 0 ? true : false;
|
||
}
|
||
if (minSize != 0 && !xSignFlag) {
|
||
return minSize > 0 ? false : true;
|
||
}
|
||
while (i > 0 && x->GetDigit(i) == y->GetDigit(i)) {
|
||
i--;
|
||
}
|
||
if (i < 0) {
|
||
return false;
|
||
}
|
||
if ((x->GetDigit(i) > y->GetDigit(i))) {
|
||
return xSignFlag ? true : false;
|
||
} else if ((x->GetDigit(i) < y->GetDigit(i))) {
|
||
return !xSignFlag ? true : false;
|
||
} else {
|
||
return false;
|
||
}
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::RightShiftHelper(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
||
{
|
||
std::string shiftBinay = BigIntHelper::GetBinary(x);
|
||
std::string revTemp = std::string(shiftBinay.rbegin(), shiftBinay.rend());
|
||
for (uint32_t i = 0; i < y->GetLength(); i++) {
|
||
revTemp = revTemp.erase(0, y->GetDigit(i));
|
||
}
|
||
std::string finalBinay = std::string(revTemp.rbegin(), revTemp.rend());
|
||
if (finalBinay.empty()) {
|
||
finalBinay = "0";
|
||
}
|
||
JSHandle<BigInt> bigint = BigIntHelper::SetBigInt(thread, finalBinay, BINARY);
|
||
if (x->GetSign()) {
|
||
SetDigit(thread, bigint, 0, bigint->GetDigit(0) + 1);
|
||
}
|
||
bigint->SetSign(x->GetSign());
|
||
return BigIntHelper::RightTruncate(thread, bigint);
|
||
}
|
||
|
||
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)
|
||
{
|
||
std::string shiftBinay = BigIntHelper::GetBinary(x);
|
||
for (size_t i = 0; i < y->GetLength(); i++) {
|
||
shiftBinay = shiftBinay.append(y->GetDigit(i), '0');
|
||
}
|
||
JSHandle<BigInt> bigint = BigIntHelper::SetBigInt(thread, shiftBinay, BINARY);
|
||
bigint->SetSign(x->GetSign());
|
||
return BigIntHelper::RightTruncate(thread, bigint);
|
||
}
|
||
|
||
JSTaggedValue BigInt::UnsignedRightShift(JSThread *thread)
|
||
{
|
||
THROW_TYPE_ERROR_AND_RETURN(thread, "BigInts have no unsigned right shift, use >> instead",
|
||
JSTaggedValue::Exception());
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::copy(JSThread *thread, JSHandle<BigInt> x)
|
||
{
|
||
uint32_t len = x->GetLength();
|
||
JSHandle<BigInt> temp = CreateBigint(thread, len);
|
||
for (uint32_t i = 0; i < len; i++) {
|
||
SetDigit(thread, temp, i, x->GetDigit(i));
|
||
}
|
||
temp->SetSign(x->GetSign());
|
||
return temp;
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::UnaryMinus(JSThread *thread, JSHandle<BigInt> x)
|
||
{
|
||
if (x->IsZero()) {
|
||
return x;
|
||
}
|
||
JSHandle<BigInt> y = copy(thread, x);
|
||
y->SetSign(!y->GetSign());
|
||
return y;
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::BitwiseNOT(JSThread *thread, JSHandle<BigInt> x)
|
||
{
|
||
// 6.1.6.2.2 BigInt::bitwiseNOT ( 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()) {
|
||
return BigIntHelper::SetBigInt(thread, "1");
|
||
}
|
||
|
||
if (base->IsZero()) {
|
||
return BigIntHelper::SetBigInt(thread, "0");
|
||
}
|
||
uint32_t EValue = exponent->GetDigit(0);
|
||
if (EValue == 1) {
|
||
return base;
|
||
}
|
||
uint32_t j = exponent->GetDigit(0) - 1;
|
||
std::string a = BigIntHelper::GetBinary(base);
|
||
a = BigIntHelper::Conversion(a, DECIMAL, BINARY);
|
||
std::string b = a;
|
||
for (uint32_t i = 0; i < j; ++i) {
|
||
b = BigIntHelper::MultiplyImpl(b, a);
|
||
}
|
||
if (exponent->GetDigit(0) & 1) {
|
||
if (base->GetSign()) {
|
||
b = "-" + b;
|
||
}
|
||
}
|
||
return BigIntHelper::SetBigInt(thread, b, DECIMAL);
|
||
}
|
||
std::string BigIntHelper::MultiplyImpl(std::string &a, std::string &b)
|
||
{
|
||
int size1 = a.size();
|
||
int size2 = b.size();
|
||
std::string str(size1 + size2, '0');
|
||
for (int i = size2 - 1; i >= 0; --i) {
|
||
int mulflag = 0;
|
||
int addflag = 0;
|
||
for (int j = size1 - 1; j >= 0; --j) {
|
||
int temp1 = (b[i] - '0') * (a[j] - '0') + mulflag;
|
||
mulflag = temp1 / 10; // 10:help to Remove single digits
|
||
temp1 = temp1 % 10; // 10:help to Take single digit
|
||
int temp2 = str[i + j + 1] - '0' + temp1 + addflag;
|
||
str[i + j + 1] = temp2 % 10 + 48; // 2 and 10 and 48 is number
|
||
addflag = temp2 / 10;
|
||
}
|
||
str[i] += mulflag + addflag;
|
||
}
|
||
if (str[0] == '0') {
|
||
str = str.substr(1, str.size());
|
||
}
|
||
return str;
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::Multiply(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
||
{
|
||
if (x->IsZero()) {
|
||
return x;
|
||
}
|
||
if (y->IsZero()) {
|
||
return y;
|
||
}
|
||
std::string left = BigIntHelper::GetBinary(x);
|
||
std::string right = BigIntHelper::GetBinary(y);
|
||
left = BigIntHelper::Conversion(left, DECIMAL, BINARY);
|
||
right = BigIntHelper::Conversion(right, DECIMAL, BINARY);
|
||
std::string ab = BigIntHelper::MultiplyImpl(left, right);
|
||
if (x->GetSign() != y->GetSign()) {
|
||
ab = "-" + ab;
|
||
}
|
||
return BigIntHelper::SetBigInt(thread, ab, DECIMAL);
|
||
}
|
||
|
||
std::string BigIntHelper::DeZero(std::string &a)
|
||
{
|
||
size_t i;
|
||
for (i = 0; i < a.length(); i++) {
|
||
if (a.at(i) > 48) { // 48 is ascill of '0'
|
||
break;
|
||
}
|
||
}
|
||
if (i == a.length()) {
|
||
return "0";
|
||
}
|
||
a.erase(0, i);
|
||
return a;
|
||
}
|
||
|
||
Comparestr BigInt::ComString(std::string &a, std::string &b)
|
||
{
|
||
if (a.length() > b.length()) {
|
||
return Comparestr::GREATER;
|
||
}
|
||
if (a.length() < b.length()) {
|
||
return Comparestr::LESS;
|
||
}
|
||
for (size_t i = 0; i < a.length(); i++) {
|
||
if (a.at(i) > b.at(i)) {
|
||
return Comparestr::GREATER;
|
||
}
|
||
if (a.at(i) < b.at(i)) {
|
||
return Comparestr::LESS;
|
||
}
|
||
}
|
||
return Comparestr::EQUAL;
|
||
}
|
||
|
||
std::string BigIntHelper::DevStr(std::string &strValue)
|
||
{
|
||
size_t i = 0;
|
||
for (i = 0; i < strValue.length(); i++) {
|
||
if (strValue.at(i) >= 48 && strValue.at(i) <= 57) { // 48 and 57 is '0' and '9'
|
||
strValue.at(i) -= 48; // 48:'0'
|
||
}
|
||
if (strValue.at(i) >= 97 && strValue.at(i) <= 122) { // 97 and 122 is 'a' and 'z'
|
||
strValue.at(i) -= 87; // 87 control result is greater than 10
|
||
}
|
||
}
|
||
return strValue;
|
||
}
|
||
|
||
std::string BigIntHelper::Minus(std::string &a, std::string &b)
|
||
{
|
||
a = DeZero(a);
|
||
b = DeZero(b);
|
||
size_t i = 0;
|
||
int j = 0;
|
||
std::string res = "0";
|
||
std::string result1;
|
||
std::string result2;
|
||
std::string dsymbol = "-";
|
||
if (BigInt::ComString(a, b) == Comparestr::EQUAL) {
|
||
return res;
|
||
}
|
||
if (BigInt::ComString(a, b) == Comparestr::GREATER) {
|
||
result1 = a;
|
||
result2 = b;
|
||
}
|
||
if (BigInt::ComString(a, b) == Comparestr::LESS) {
|
||
result1 = b;
|
||
result2 = a;
|
||
j = -1;
|
||
}
|
||
reverse(result1.begin(), result1.end());
|
||
reverse(result2.begin(), result2.end());
|
||
result1 = DevStr(result1);
|
||
result2 = DevStr(result2);
|
||
for (i = 0; i < result2.length(); i++) {
|
||
result1.at(i) = result1.at(i) - result2.at(i);
|
||
}
|
||
for (i = 0; i < result1.length() - 1; i++) {
|
||
if (result1.at(i) < 0) {
|
||
result1.at(i) += BigInt::DECIMAL;
|
||
result1.at(i + 1)--;
|
||
}
|
||
}
|
||
for (i = result1.length() - 1; i >= 0; i--) {
|
||
if (result1.at(i) > 0) {
|
||
break;
|
||
}
|
||
}
|
||
result1.erase(i + 1, result1.length());
|
||
for (i = 0; i < result1.length(); i++) {
|
||
if (result1.at(i) >= 10) { // 10:Hexadecimal a
|
||
result1.at(i) += 87; // 87:control result is greater than 97
|
||
}
|
||
if (result1.at(i) < 10) { // 10: 10:Hexadecimal a
|
||
result1.at(i) += 48; // 48:'0'
|
||
}
|
||
}
|
||
reverse(result1.begin(), result1.end());
|
||
if (j == -1) {
|
||
result1.insert(0, dsymbol);
|
||
}
|
||
return result1;
|
||
}
|
||
|
||
std::string BigIntHelper::Divide(std::string &a, std::string &b)
|
||
{
|
||
size_t i = 0;
|
||
size_t j = 0;
|
||
std::string result1;
|
||
std::string result2;
|
||
std::string dsy;
|
||
std::string quotient;
|
||
if (BigInt::ComString(a, b) == Comparestr::EQUAL) {
|
||
return "1";
|
||
}
|
||
if (BigInt::ComString(a, b) == Comparestr::LESS) {
|
||
return "0";
|
||
}
|
||
result1 = DeZero(a);
|
||
result2 = DeZero(b);
|
||
dsy = "";
|
||
quotient = "";
|
||
for (i = 0; i < result1.length(); i++) {
|
||
j = 0;
|
||
dsy = dsy + result1.at(i);
|
||
dsy = DeZero(dsy);
|
||
while (BigInt::ComString(dsy, b) == Comparestr::EQUAL ||
|
||
BigInt::ComString(dsy, b) == Comparestr::GREATER) {
|
||
dsy = Minus(dsy, b);
|
||
dsy = DeZero(dsy);
|
||
j++;
|
||
}
|
||
quotient = quotient + "0";
|
||
quotient.at(i) = j;
|
||
}
|
||
for (i = 0; i < quotient.length(); i++) {
|
||
if (quotient.at(i) >= 10) { // 10 is number
|
||
quotient.at(i) += 87; // 87 is number
|
||
}
|
||
if (quotient.at(i) < 10) { // 10 is number
|
||
quotient.at(i) += 48; // 48 is number
|
||
}
|
||
}
|
||
quotient = DeZero(quotient);
|
||
return quotient;
|
||
}
|
||
|
||
JSHandle<BigInt> BigIntHelper::DivideImpl(JSThread *thread, JSHandle<BigInt> x, JSHandle<BigInt> y)
|
||
{
|
||
std::string a = Conversion(GetBinary(x), BigInt::DECIMAL, BigInt::BINARY);
|
||
std::string b = Conversion(GetBinary(y), BigInt::DECIMAL, BigInt::BINARY);
|
||
std::string ab = Divide(a, b);
|
||
if (ab == "0") {
|
||
ab = "0";
|
||
} else if (x->GetSign() != y->GetSign()) {
|
||
ab = "-" + ab;
|
||
}
|
||
return SetBigInt(thread, ab, BigInt::DECIMAL);
|
||
}
|
||
|
||
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);
|
||
}
|
||
return BigIntHelper::DivideImpl(thread, x, y);
|
||
}
|
||
|
||
|
||
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);
|
||
}
|
||
if (n->IsZero()) {
|
||
return n;
|
||
}
|
||
JSHandle<BigInt> q = Divide(thread, n, d);
|
||
JSHandle<BigInt> p = Multiply(thread, q, d);
|
||
return Subtract(thread, n, p);
|
||
}
|
||
|
||
JSHandle<BigInt> BigInt::FloorMod(JSThread *thread, JSHandle<BigInt> leftVal, JSHandle<BigInt> rightVal)
|
||
{
|
||
if (leftVal->GetSign()) {
|
||
JSHandle<BigInt> quotientVal = Divide(thread, leftVal, rightVal);
|
||
if (quotientVal->IsZero()) {
|
||
return Add(thread, leftVal, rightVal);
|
||
} else {
|
||
JSHandle<BigInt> num = Multiply(thread, quotientVal, rightVal);
|
||
if (Equal(num.GetTaggedValue(), leftVal.GetTaggedValue())) {
|
||
return Int32ToBigInt(thread, 0);
|
||
} else {
|
||
return Subtract(thread, leftVal, Subtract(thread, num, rightVal));
|
||
}
|
||
}
|
||
}
|
||
return Remainder(thread, leftVal, rightVal);
|
||
}
|
||
|
||
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).
|
||
if (LessThan(resValue.GetTaggedValue(), modValue.GetTaggedValue()) ||
|
||
Equal(resValue.GetTaggedValue(), modValue.GetTaggedValue())) {
|
||
return Subtract(thread, modValue, tValue).GetTaggedValue();
|
||
}
|
||
return modValue.GetTaggedValue();
|
||
}
|
||
|
||
JSTaggedNumber BigInt::BigIntToNumber(JSThread *thread, JSHandle<BigInt> bigint)
|
||
{
|
||
std::string bigintStr = ToStdString(thread, bigint, HEXADECIMAL);
|
||
bool sign = false;
|
||
if (bigintStr[0] == '-') {
|
||
bigintStr = bigintStr.substr(1); // 1 : dump '-'
|
||
sign = true;
|
||
}
|
||
bigintStr = "0x" + bigintStr;
|
||
ObjectFactory *factory = thread->GetEcmaVM()->GetFactory();
|
||
JSHandle<EcmaString> str = factory->NewFromStdStringUnCheck(bigintStr, true);
|
||
JSHandle<JSTaggedValue> numberStr(thread, str.GetTaggedValue());
|
||
JSTaggedNumber number = JSTaggedValue::ToNumber(thread, numberStr);
|
||
if (sign) {
|
||
return JSTaggedNumber(-number.GetNumber());
|
||
}
|
||
return number;
|
||
}
|
||
|
||
int CompareToBitsLen(JSHandle<BigInt> bigint, int numBitLen, int &preZero)
|
||
{
|
||
uint32_t bigintLen = bigint->GetLength();
|
||
uint32_t BigintHead = bigint->GetDigit(bigintLen - 1);
|
||
uint32_t bits = BigInt::DATEBITS;
|
||
while (bits) {
|
||
bits--;
|
||
if (((BigintHead >> bits) | 0) != 0) {
|
||
break;
|
||
}
|
||
preZero++;
|
||
}
|
||
|
||
int bigintBitLen = bigintLen * BigInt::DATEBITS - preZero;
|
||
bool bigintSign = bigint->GetSign();
|
||
if (bigintBitLen > numBitLen) {
|
||
return bigintSign ? 0 : 1;
|
||
}
|
||
|
||
if (bigintBitLen < numBitLen) {
|
||
return bigintSign ? 1 : 0;
|
||
}
|
||
return -1;
|
||
}
|
||
|
||
ComparisonResult BigInt::CompareWithNumber(JSThread *thread, JSHandle<BigInt> bigint, JSHandle<JSTaggedValue> number)
|
||
{
|
||
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;
|
||
memcpy_s(&bits, sizeof(bits), &num, sizeof(num));
|
||
int exponential = (bits >> 52) & 0x7FF;
|
||
|
||
// Take out bits 62-52 (11 bits in total) and subtract 1023
|
||
int integerDigits = exponential - 0x3FF;
|
||
uint64_t mantissa = (bits & 0x000FFFFFFFFFFFFF) | 0x0010000000000000;
|
||
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
|
||
int preZero = 0;
|
||
int res = CompareToBitsLen(bigint, integerDigits + 1, preZero);
|
||
if (res == 0) {
|
||
return ComparisonResult::LESS;
|
||
} else if (res == 1) {
|
||
return ComparisonResult::GREAT;
|
||
}
|
||
int mantissaSize = 52; // mantissaSize
|
||
uint32_t bigintLen = bigint->GetLength();
|
||
int leftover = 0;
|
||
bool IsFirstInto = true;
|
||
for (int index = bigintLen - 1; index >= 0; --index) {
|
||
uint32_t doubleNum = 0;
|
||
uint32_t BigintNum = bigint->GetDigit(index);
|
||
if (IsFirstInto) {
|
||
IsFirstInto = false;
|
||
leftover = mantissaSize - BigInt::DATEBITS + preZero + 1;
|
||
doubleNum = static_cast<uint32_t>(mantissa >> leftover);
|
||
mantissa = mantissa << (64 - leftover); // 64 double bits
|
||
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;
|
||
}
|
||
} // namespace
|