Commit d84efe12 authored by Jakob Kummerow's avatar Jakob Kummerow Committed by Commit Bot

[bigint] Implement BigInt::Exponentiate

Bug: v8:6791
Change-Id: I976876a4956b5c65f6f3788389f42d394d08dc99
Reviewed-on: https://chromium-review.googlesource.com/788513
Commit-Queue: Jakob Kummerow <jkummerow@chromium.org>
Reviewed-by: 's avatarGeorg Neis <neis@chromium.org>
Cr-Commit-Position: refs/heads/master@{#49773}
parent ae26aab1
......@@ -520,6 +520,7 @@ class ErrorUtils : public AllStatic {
T(UnsupportedSuper, "Unsupported reference to 'super'") \
/* RangeError */ \
T(BigIntDivZero, "Division by zero") \
T(BigIntNegativeExponent, "Exponent must be positive") \
T(BigIntTooBig, "Maximum BigInt size exceeded") \
T(DateRange, "Provided date is not in valid range.") \
T(ExpectedTimezoneID, \
......
......@@ -304,7 +304,71 @@ MaybeHandle<BigInt> BigInt::BitwiseNot(Handle<BigInt> x) {
MaybeHandle<BigInt> BigInt::Exponentiate(Handle<BigInt> base,
Handle<BigInt> exponent) {
UNIMPLEMENTED(); // TODO(jkummerow): Implement.
Isolate* isolate = base->GetIsolate();
// 1. If exponent is < 0, throw a RangeError exception.
if (exponent->sign()) {
THROW_NEW_ERROR(isolate,
NewRangeError(MessageTemplate::kBigIntNegativeExponent),
BigInt);
}
// 2. If base is 0n and exponent is 0n, return 1n.
if (exponent->is_zero()) {
return MutableBigInt::NewFromInt(isolate, 1);
}
// 3. Return a BigInt representing the mathematical value of base raised
// to the power exponent.
if (base->is_zero()) return base;
if (base->length() == 1 && base->digit(0) == 1) return base;
// For all bases >= 2, very large exponents would lead to unrepresentable
// results.
STATIC_ASSERT(kMaxLengthBits < std::numeric_limits<digit_t>::max());
if (exponent->length() > 1) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
BigInt);
}
digit_t exp_value = exponent->digit(0);
if (exp_value == 1) return base;
if (exp_value >= kMaxLengthBits) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
BigInt);
}
STATIC_ASSERT(kMaxLengthBits <= kMaxInt);
int n = static_cast<int>(exp_value);
if (base->length() == 1 && base->digit(0) == 2) {
// Fast path for 2^n.
int needed_digits = 1 + (n / kDigitBits);
Handle<MutableBigInt> result =
MutableBigInt::New(isolate, needed_digits).ToHandleChecked();
result->InitializeDigits(needed_digits);
// All bits are zero. Now set the n-th bit.
digit_t msd = static_cast<digit_t>(1) << (n % kDigitBits);
result->set_digit(needed_digits - 1, msd);
// Result is negative for odd powers of -2n.
if (base->sign()) result->set_sign((n & 1) != 0);
return MutableBigInt::MakeImmutable(result);
}
Handle<BigInt> result;
Handle<BigInt> running_square = base;
// This implicitly sets the result's sign correctly.
if (n & 1) result = base;
n >>= 1;
for (; n != 0; n >>= 1) {
if (!Multiply(running_square, running_square).ToHandle(&running_square)) {
THROW_NEW_ERROR(isolate, NewRangeError(MessageTemplate::kBigIntTooBig),
BigInt);
}
if (n & 1) {
if (result.is_null()) {
result = running_square;
} else {
if (!Multiply(result, running_square).ToHandle(&result)) {
THROW_NEW_ERROR(
isolate, NewRangeError(MessageTemplate::kBigIntTooBig), BigInt);
}
}
}
}
return result;
}
MaybeHandle<BigInt> BigInt::Multiply(Handle<BigInt> x, Handle<BigInt> y) {
......@@ -1617,8 +1681,8 @@ Handle<BigInt> MutableBigInt::RightShiftByMaximum(Isolate* isolate, bool sign) {
Maybe<BigInt::digit_t> MutableBigInt::ToShiftAmount(Handle<BigIntBase> x) {
if (x->length() > 1) return Nothing<digit_t>();
digit_t value = x->digit(0);
STATIC_ASSERT(kMaxLength * kDigitBits < std::numeric_limits<digit_t>::max());
if (value > kMaxLength * kDigitBits) return Nothing<digit_t>();
STATIC_ASSERT(kMaxLengthBits < std::numeric_limits<digit_t>::max());
if (value > kMaxLengthBits) return Nothing<digit_t>();
return Just(value);
}
......
......@@ -24,7 +24,7 @@ class BigIntBase : public HeapObject {
return LengthBits::decode(static_cast<uint32_t>(bitfield));
}
// The maximum length that the current implementation supports would be
// The maximum kMaxLength that the current implementation supports would be
// kMaxInt / kDigitBits. However, we use a lower limit for now, because
// raising it later is easier than lowering it.
// Support up to 1 million bits.
......
......@@ -108,7 +108,7 @@ RUNTIME_FUNCTION(Runtime_BigIntBinaryOp) {
result = BigInt::Remainder(left, right);
break;
case Operation::kExponentiate:
UNIMPLEMENTED();
result = BigInt::Exponentiate(left, right);
break;
case Operation::kBitwiseAnd:
result = BigInt::BitwiseAnd(left, right);
......
......@@ -244,10 +244,9 @@
assertEquals(9223372036854775808n - 42n, BigInt.asUintN(63, -42n));
assertEquals(18446744073709551616n - 42n, BigInt.asUintN(64, -42n));
assertEquals(36893488147419103232n - 42n, BigInt.asUintN(65, -42n));
// TODO(neis): Enable once we have exponentation.
// assertEquals(2n**127n - 42n, BigInt.asUintN(127, -42n));
// assertEquals(2n**128n - 42n, BigInt.asUintN(128, -42n));
// assertEquals(2n**129n - 42n, BigInt.asUintN(129, -42n));
assertEquals(2n**127n - 42n, BigInt.asUintN(127, -42n));
assertEquals(2n**128n - 42n, BigInt.asUintN(128, -42n));
assertEquals(2n**129n - 42n, BigInt.asUintN(129, -42n));
}{
assertEquals(0n, BigInt.asUintN(0, 4294967295n));
assertEquals(1n, BigInt.asUintN(1, 4294967295n));
......@@ -274,10 +273,9 @@
BigInt.asUintN(64,-4294967295n));
assertEquals(36893488147419103232n - 4294967295n,
BigInt.asUintN(65, -4294967295n));
// TODO(neis): Enable once we have exponentation.
// assertEquals(2n**127n - 42n, BigInt.asUintN(127, -4294967295n));
// assertEquals(2n**128n - 42n, BigInt.asUintN(128, -4294967295n));
// assertEquals(2n**129n - 42n, BigInt.asUintN(129, -4294967295n));
assertEquals(2n**127n - 4294967295n, BigInt.asUintN(127, -4294967295n));
assertEquals(2n**128n - 4294967295n, BigInt.asUintN(128, -4294967295n));
assertEquals(2n**129n - 4294967295n, BigInt.asUintN(129, -4294967295n));
}{
assertEquals(42n, BigInt.asUintN(2**32, 42n));
assertEquals(4294967295n, BigInt.asUintN(2**32, 4294967295n));
......
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
// Flags: --allow-natives-syntax --harmony-bigint
assertEquals(1n, 0n ** 0n);
assertEquals(0n, 0n ** 1n);
assertEquals(0n, 0n ** 23n);
assertEquals(1n, 1n ** 0n);
assertEquals(1n, 1n ** 1n);
assertEquals(1n, 99n ** 0n);
assertEquals(2n, 2n ** 1n);
assertEquals(4n, 2n ** 2n);
assertEquals(8n, 2n ** 3n);
assertEquals(16n, 2n ** 4n);
assertEquals(151115727451828646838272n, 2n ** 77n);
assertEquals(3n, 3n ** 1n);
assertEquals(9n, 3n ** 2n);
assertEquals(27n, 3n ** 3n);
assertEquals(81n, 3n ** 4n);
assertEquals(243n, 3n ** 5n);
assertEquals(30903154382632612361920641803529n, 3n ** 66n);
assertEquals(1n, (-2n) ** 0n);
assertEquals(-2n, (-2n) ** 1n);
assertEquals(4n, (-2n) ** 2n);
assertEquals(-8n, (-2n) ** 3n);
assertEquals(16n, (-2n) ** 4n);
assertEquals(-32n, (-2n) ** 5n);
assertEquals(1n, (-3n) ** 0n);
assertEquals(-3n, (-3n) ** 1n);
assertEquals(9n, (-3n) ** 2n);
assertEquals(-27n, (-3n) ** 3n);
assertEquals(81n, (-3n) ** 4n);
assertEquals(-243n, (-3n) ** 5n);
assertThrows(() => 3n ** -2n, RangeError); // Negative exponent.
assertThrows(() => 2n ** (1024n ** 3n), RangeError); // Too big.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment