bug 1471134 - Part 1: Define methods for basic BigInt arithmetic. r=Waldo

This commit is contained in:
Robin Templeton 2018-07-08 21:12:00 +03:00
parent ad48d9c804
commit e7f485bfdb
3 changed files with 118 additions and 0 deletions

View File

@ -652,6 +652,7 @@ MSG_DEF(JSMSG_RESPONSE_ALREADY_CONSUMED, 0, JSEXN_TYPEERR, "Res
// BigInt
MSG_DEF(JSMSG_BIGINT_TO_NUMBER, 0, JSEXN_TYPEERR, "can't convert BigInt to number")
MSG_DEF(JSMSG_NUMBER_TO_BIGINT, 0, JSEXN_RANGEERR, "can't convert non-finite number to BigInt")
MSG_DEF(JSMSG_BIGINT_TOO_LARGE, 0, JSEXN_RANGEERR, "BigInt is too large to allocate")
MSG_DEF(JSMSG_BIGINT_DIVISION_BY_ZERO, 0, JSEXN_RANGEERR, "BigInt division by zero")
MSG_DEF(JSMSG_BIGINT_NEGATIVE_EXPONENT, 0, JSEXN_RANGEERR, "BigInt negative exponent")
MSG_DEF(JSMSG_BIGINT_INVALID_SYNTAX, 0, JSEXN_SYNTAXERR, "invalid BigInt syntax")

View File

@ -171,6 +171,116 @@ BigInt::copy(JSContext* cx, HandleBigInt x)
return bi;
}
// BigInt proposal section 1.1.7
BigInt*
BigInt::add(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_add(z->num_, x->num_, y->num_);
return z;
}
// BigInt proposal section 1.1.8
BigInt*
BigInt::sub(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_sub(z->num_, x->num_, y->num_);
return z;
}
// BigInt proposal section 1.1.4
BigInt*
BigInt::mul(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_mul(z->num_, x->num_, y->num_);
return z;
}
// BigInt proposal section 1.1.5
BigInt*
BigInt::div(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
// Step 1.
if (mpz_size(y->num_) == 0) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BIGINT_DIVISION_BY_ZERO);
return nullptr;
}
// Steps 2-3.
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_tdiv_q(z->num_, x->num_, y->num_);
return z;
}
// BigInt proposal section 1.1.6
BigInt*
BigInt::mod(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
// Step 1.
if (mpz_size(y->num_) == 0) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BIGINT_DIVISION_BY_ZERO);
return nullptr;
}
// Steps 2-4.
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_tdiv_r(z->num_, x->num_, y->num_);
return z;
}
// BigInt proposal section 1.1.3
BigInt*
BigInt::pow(JSContext* cx, HandleBigInt x, HandleBigInt y)
{
// Step 1.
if (mpz_sgn(y->num_) < 0) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BIGINT_NEGATIVE_EXPONENT);
return nullptr;
}
// Throw a RangeError if the exponent is too large.
if (!mpz_fits_uint_p(y->num_)) {
JS_ReportErrorNumberASCII(cx, GetErrorMessage, nullptr,
JSMSG_BIGINT_TOO_LARGE);
return nullptr;
}
unsigned long int power = mpz_get_ui(y->num_);
// Steps 2-3.
BigInt* z = create(cx);
if (!z)
return nullptr;
mpz_pow_ui(z->num_, x->num_, power);
return z;
}
// BigInt proposal section 1.1.1
BigInt*
BigInt::neg(JSContext* cx, HandleBigInt x)
{
BigInt* res = create(cx);
if (!res)
return nullptr;
mpz_neg(res->num_, x->num_);
return res;
}
// BigInt proposal section 7.3
BigInt*
js::ToBigInt(JSContext* cx, HandleValue val)

View File

@ -73,6 +73,13 @@ class BigInt final : public js::gc::TenuredCell
static void init();
static BigInt* copy(JSContext* cx, Handle<BigInt*> x);
static BigInt* add(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* sub(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* mul(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* div(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* mod(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* pow(JSContext* cx, Handle<BigInt*> x, Handle<BigInt*> y);
static BigInt* neg(JSContext* cx, Handle<BigInt*> x);
static double numberValue(BigInt* x);
static JSLinearString* toString(JSContext* cx, BigInt* x, uint8_t radix);