mirror of
https://github.com/LadybirdBrowser/ladybird.git
synced 2025-01-24 02:03:06 -05:00
LibCrypto: Added static non-allocating UnsignedBigInteger operators
This changes the plus, minus, etc... operators from UnsignedBigInteger to use a static helper method. The static methods do not allocate any variables, instead all the required BigInteger output and temporary variables are required on call as parameters. This change already optimizes the number of allocations in complex operations such as multiply or divide, by having a single allocation per call (instead of one per loop). This new API also provides a way to limit the number of allocations for complex computations in other parts of the code. This is done by using these helpers in any place that currently makes use of the standard operators.
This commit is contained in:
parent
d008a38f93
commit
28ea347e55
Notes:
sideshowbarker
2024-07-19 07:01:05 +09:00
Author: https://github.com/Dexesttp Commit: https://github.com/SerenityOS/serenity/commit/28ea347e55b Pull-request: https://github.com/SerenityOS/serenity/pull/2064
2 changed files with 270 additions and 144 deletions
|
@ -96,6 +96,21 @@ String UnsignedBigInteger::to_base10() const
|
|||
return builder.to_string();
|
||||
}
|
||||
|
||||
void UnsignedBigInteger::set_to_0()
|
||||
{
|
||||
m_words.clear_with_capacity();
|
||||
m_is_invalid = false;
|
||||
}
|
||||
|
||||
void UnsignedBigInteger::set_to(const UnsignedBigInteger& other)
|
||||
{
|
||||
m_is_invalid = other.m_is_invalid;
|
||||
m_words.clear_with_capacity();
|
||||
m_words.ensure_capacity(other.m_words.size());
|
||||
for (size_t i = 0; i < other.m_words.size(); ++i)
|
||||
m_words.unchecked_append(other.m_words[i]);
|
||||
}
|
||||
|
||||
size_t UnsignedBigInteger::trimmed_length() const
|
||||
{
|
||||
size_t num_leading_zeroes = 0;
|
||||
|
@ -106,161 +121,61 @@ size_t UnsignedBigInteger::trimmed_length() const
|
|||
return length() - num_leading_zeroes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N) where N is the number of words in the larger number
|
||||
*/
|
||||
UnsignedBigInteger UnsignedBigInteger::plus(const UnsignedBigInteger& other) const
|
||||
{
|
||||
const UnsignedBigInteger* const longer = (length() > other.length()) ? this : &other;
|
||||
const UnsignedBigInteger* const shorter = (longer == &other) ? this : &other;
|
||||
UnsignedBigInteger result;
|
||||
|
||||
u8 carry = 0;
|
||||
|
||||
result.m_words.ensure_capacity(longer->length() + 1);
|
||||
|
||||
for (size_t i = 0; i < shorter->length(); ++i) {
|
||||
u32 word_addition_result = shorter->m_words[i] + longer->m_words[i];
|
||||
u8 carry_out = 0;
|
||||
// if there was a carry, the result will be smaller than any of the operands
|
||||
if (word_addition_result + carry < shorter->m_words[i]) {
|
||||
carry_out = 1;
|
||||
}
|
||||
if (carry) {
|
||||
word_addition_result++;
|
||||
}
|
||||
carry = carry_out;
|
||||
result.m_words.unchecked_append(word_addition_result);
|
||||
}
|
||||
|
||||
for (size_t i = shorter->length(); i < longer->length(); ++i) {
|
||||
u32 word_addition_result = longer->m_words[i] + carry;
|
||||
|
||||
carry = 0;
|
||||
if (word_addition_result < longer->m_words[i]) {
|
||||
carry = 1;
|
||||
}
|
||||
result.m_words.unchecked_append(word_addition_result);
|
||||
}
|
||||
if (carry) {
|
||||
result.m_words.unchecked_append(carry);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N) where N is the number of words in the larger number
|
||||
*/
|
||||
UnsignedBigInteger UnsignedBigInteger::minus(const UnsignedBigInteger& other) const
|
||||
FLATTEN UnsignedBigInteger UnsignedBigInteger::plus(const UnsignedBigInteger& other) const
|
||||
{
|
||||
UnsignedBigInteger result;
|
||||
|
||||
if (*this < other) {
|
||||
return UnsignedBigInteger::create_invalid();
|
||||
}
|
||||
|
||||
u8 borrow = 0;
|
||||
auto own_length = length(), other_length = other.length();
|
||||
|
||||
result.m_words.ensure_capacity(own_length);
|
||||
|
||||
for (size_t i = 0; i < own_length; ++i) {
|
||||
u32 other_word = (i < other_length) ? other.m_words[i] : 0;
|
||||
i64 temp = static_cast<i64>(m_words[i]) - static_cast<i64>(other_word) - static_cast<i64>(borrow);
|
||||
// If temp < 0, we had an underflow
|
||||
borrow = (temp >= 0) ? 0 : 1;
|
||||
if (temp < 0) {
|
||||
temp += (UINT32_MAX + 1);
|
||||
}
|
||||
result.m_words.append(temp);
|
||||
}
|
||||
|
||||
// This assertion should not fail, because we verified that *this>=other at the beginning of the function
|
||||
ASSERT(borrow == 0);
|
||||
add_without_allocation(*this, other, result);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
UnsignedBigInteger UnsignedBigInteger::shift_left(size_t num_bits) const
|
||||
FLATTEN UnsignedBigInteger UnsignedBigInteger::minus(const UnsignedBigInteger& other) const
|
||||
{
|
||||
// We can only do shift operations on individual words
|
||||
// where the shift amount is <= size of word (32).
|
||||
// But we do know how to shift by a multiple of word size (e.g 64=32*2)
|
||||
// So we first shift the result by how many whole words fit in 'num_bits'
|
||||
UnsignedBigInteger temp_result = shift_left_by_n_words(num_bits / UnsignedBigInteger::BITS_IN_WORD);
|
||||
UnsignedBigInteger result;
|
||||
|
||||
// And now we shift by the leftover amount of bits
|
||||
num_bits %= UnsignedBigInteger::BITS_IN_WORD;
|
||||
subtract_without_allocation(*this, other, result);
|
||||
|
||||
UnsignedBigInteger result(temp_result);
|
||||
|
||||
for (size_t i = 0; i < temp_result.length(); ++i) {
|
||||
u32 current_word_of_temp_result = temp_result.shift_left_get_one_word(num_bits, i);
|
||||
result.m_words[i] = current_word_of_temp_result;
|
||||
}
|
||||
|
||||
// Shifting the last word can produce a carry
|
||||
u32 carry_word = temp_result.shift_left_get_one_word(num_bits, temp_result.length());
|
||||
if (carry_word != 0) {
|
||||
result = result.plus(UnsignedBigInteger(carry_word).shift_left_by_n_words(temp_result.length()));
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N^2) where N is the number of words in the larger number
|
||||
* Multiplcation method:
|
||||
* An integer is equal to the sum of the powers of two
|
||||
* according to the indexes of its 'on' bits.
|
||||
* So to multiple x*y, we go over each '1' bit in x (say the i'th bit),
|
||||
* and add y<<i to the result.
|
||||
*/
|
||||
FLATTEN UnsignedBigInteger UnsignedBigInteger::shift_left(size_t num_bits) const
|
||||
{
|
||||
UnsignedBigInteger output;
|
||||
UnsignedBigInteger temp_result;
|
||||
UnsignedBigInteger temp_plus;
|
||||
|
||||
shift_left_without_allocation(*this, num_bits, temp_result, temp_plus, output);
|
||||
|
||||
return output;
|
||||
}
|
||||
|
||||
FLATTEN UnsignedBigInteger UnsignedBigInteger::multiplied_by(const UnsignedBigInteger& other) const
|
||||
{
|
||||
UnsignedBigInteger result;
|
||||
// iterate all bits
|
||||
for (size_t word_index = 0; word_index < length(); ++word_index) {
|
||||
for (size_t bit_index = 0; bit_index < UnsignedBigInteger::BITS_IN_WORD; ++bit_index) {
|
||||
// If the bit is off - skip over it
|
||||
if (!(m_words[word_index] & (1 << bit_index)))
|
||||
continue;
|
||||
UnsignedBigInteger temp_shift_result;
|
||||
UnsignedBigInteger temp_shift_plus;
|
||||
UnsignedBigInteger temp_shift;
|
||||
UnsignedBigInteger temp_plus;
|
||||
|
||||
multiply_without_allocation(*this, other, temp_shift_result, temp_shift_plus, temp_shift, temp_plus, result);
|
||||
|
||||
const size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
|
||||
auto shift_result = other.shift_left(shift_amount);
|
||||
result = result.plus(shift_result);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N^2) where N is the number of words in the larger number
|
||||
* Division method:
|
||||
* We loop over the bits of the divisor, attempting to subtract divisor<<i from the dividend.
|
||||
* If the result is non-negative, it means that divisor*2^i "fits" in the dividend,
|
||||
* so we set the ith bit in the quotient and reduce divisor<<i from the dividend.
|
||||
* When we're done, what's left from the dividend is the remainder.
|
||||
*/
|
||||
FLATTEN UnsignedDivisionResult UnsignedBigInteger::divided_by(const UnsignedBigInteger& divisor) const
|
||||
{
|
||||
UnsignedBigInteger leftover_dividend(*this);
|
||||
UnsignedBigInteger quotient;
|
||||
UnsignedBigInteger remainder;
|
||||
|
||||
// iterate all bits
|
||||
for (int word_index = trimmed_length() - 1; word_index >= 0; --word_index) {
|
||||
for (int bit_index = UnsignedBigInteger::BITS_IN_WORD - 1; bit_index >= 0; --bit_index) {
|
||||
UnsignedBigInteger temp_shift_result;
|
||||
UnsignedBigInteger temp_shift_plus;
|
||||
UnsignedBigInteger temp_shift;
|
||||
UnsignedBigInteger temp_minus;
|
||||
|
||||
const size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
|
||||
UnsignedBigInteger divisor_shifted = divisor.shift_left(shift_amount);
|
||||
divide_without_allocation(*this, divisor, temp_shift_result, temp_shift_plus, temp_shift, temp_minus, quotient, remainder);
|
||||
|
||||
UnsignedBigInteger temp_subtraction_result = leftover_dividend.minus(divisor_shifted);
|
||||
if (!temp_subtraction_result.is_invalid()) {
|
||||
leftover_dividend = temp_subtraction_result;
|
||||
quotient.set_bit_inplace(shift_amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
return UnsignedDivisionResult { quotient, leftover_dividend };
|
||||
return UnsignedDivisionResult { quotient, remainder };
|
||||
}
|
||||
|
||||
void UnsignedBigInteger::set_bit_inplace(size_t bit_index)
|
||||
|
@ -320,39 +235,242 @@ bool UnsignedBigInteger::operator<(const UnsignedBigInteger& other) const
|
|||
return false;
|
||||
}
|
||||
|
||||
ALWAYS_INLINE UnsignedBigInteger UnsignedBigInteger::shift_left_by_n_words(const size_t number_of_words) const
|
||||
/**
|
||||
* Complexity: O(N) where N is the number of words in the larger number
|
||||
*/
|
||||
void UnsignedBigInteger::add_without_allocation(
|
||||
const UnsignedBigInteger& left,
|
||||
const UnsignedBigInteger& right,
|
||||
UnsignedBigInteger& output)
|
||||
{
|
||||
const UnsignedBigInteger* const longer = (left.length() > right.length()) ? &left : &right;
|
||||
const UnsignedBigInteger* const shorter = (longer == &right) ? &left : &right;
|
||||
|
||||
u8 carry = 0;
|
||||
|
||||
output.set_to_0();
|
||||
output.m_words.ensure_capacity(longer->length() + 1);
|
||||
|
||||
for (size_t i = 0; i < shorter->length(); ++i) {
|
||||
u32 word_addition_result = shorter->m_words[i] + longer->m_words[i];
|
||||
u8 carry_out = 0;
|
||||
// if there was a carry, the result will be smaller than any of the operands
|
||||
if (word_addition_result + carry < shorter->m_words[i]) {
|
||||
carry_out = 1;
|
||||
}
|
||||
if (carry) {
|
||||
word_addition_result++;
|
||||
}
|
||||
carry = carry_out;
|
||||
output.m_words.unchecked_append(word_addition_result);
|
||||
}
|
||||
|
||||
for (size_t i = shorter->length(); i < longer->length(); ++i) {
|
||||
u32 word_addition_result = longer->m_words[i] + carry;
|
||||
|
||||
carry = 0;
|
||||
if (word_addition_result < longer->m_words[i]) {
|
||||
carry = 1;
|
||||
}
|
||||
output.m_words.unchecked_append(word_addition_result);
|
||||
}
|
||||
if (carry) {
|
||||
output.m_words.unchecked_append(carry);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N) where N is the number of words in the larger number
|
||||
*/
|
||||
void UnsignedBigInteger::subtract_without_allocation(
|
||||
const UnsignedBigInteger& left,
|
||||
const UnsignedBigInteger& right,
|
||||
UnsignedBigInteger& output)
|
||||
{
|
||||
if (left < right) {
|
||||
output.invalidate();
|
||||
return;
|
||||
}
|
||||
|
||||
u8 borrow = 0;
|
||||
auto own_length = left.length();
|
||||
auto other_length = right.length();
|
||||
|
||||
output.set_to_0();
|
||||
output.m_words.ensure_capacity(own_length);
|
||||
|
||||
for (size_t i = 0; i < own_length; ++i) {
|
||||
u32 other_word = (i < other_length) ? right.m_words[i] : 0;
|
||||
i64 temp = static_cast<i64>(left.m_words[i]) - static_cast<i64>(other_word) - static_cast<i64>(borrow);
|
||||
// If temp < 0, we had an underflow
|
||||
borrow = (temp >= 0) ? 0 : 1;
|
||||
if (temp < 0) {
|
||||
temp += (UINT32_MAX + 1);
|
||||
}
|
||||
output.m_words.append(temp);
|
||||
}
|
||||
|
||||
// This assertion should not fail, because we verified that *this>=other at the beginning of the function
|
||||
ASSERT(borrow == 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity : O(N + num_bits % 8) where N is the number of words in the number
|
||||
* Shift method :
|
||||
* Start by shifting by whole words in num_bits (by putting missing words at the start),
|
||||
* then shift the number's words two by two by the remaining amount of bits.
|
||||
*/
|
||||
FLATTEN void UnsignedBigInteger::shift_left_without_allocation(
|
||||
const UnsignedBigInteger& number,
|
||||
size_t num_bits,
|
||||
UnsignedBigInteger& temp_result,
|
||||
UnsignedBigInteger& temp_plus,
|
||||
UnsignedBigInteger& output)
|
||||
{
|
||||
// We can only do shift operations on individual words
|
||||
// where the shift amount is <= size of word (32).
|
||||
// But we do know how to shift by a multiple of word size (e.g 64=32*2)
|
||||
// So we first shift the result by how many whole words fit in 'num_bits'
|
||||
shift_left_by_n_words(number, num_bits / UnsignedBigInteger::BITS_IN_WORD, temp_result);
|
||||
|
||||
output.set_to(temp_result);
|
||||
|
||||
// And now we shift by the leftover amount of bits
|
||||
num_bits %= UnsignedBigInteger::BITS_IN_WORD;
|
||||
|
||||
if (num_bits == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < temp_result.length(); ++i) {
|
||||
u32 current_word_of_temp_result = shift_left_get_one_word(temp_result, num_bits, i);
|
||||
output.m_words[i] = current_word_of_temp_result;
|
||||
}
|
||||
|
||||
// Shifting the last word can produce a carry
|
||||
u32 carry_word = shift_left_get_one_word(temp_result, num_bits, temp_result.length());
|
||||
if (carry_word != 0) {
|
||||
|
||||
// output += (carry_word << temp_result.length())
|
||||
// FIXME : Using temp_plus this way to transform carry_word into a bigint is not
|
||||
// efficient nor pretty. Maybe we should have an "add_with_shift" method ?
|
||||
temp_plus.set_to_0();
|
||||
temp_plus.m_words.append(carry_word);
|
||||
shift_left_by_n_words(temp_plus, temp_result.length(), temp_result);
|
||||
add_without_allocation(output, temp_result, temp_plus);
|
||||
output.set_to(temp_plus);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N^2) where N is the number of words in the larger number
|
||||
* Multiplication method:
|
||||
* An integer is equal to the sum of the powers of two
|
||||
* according to the indexes of its 'on' bits.
|
||||
* So to multiple x*y, we go over each '1' bit in x (say the i'th bit),
|
||||
* and add y<<i to the result.
|
||||
*/
|
||||
FLATTEN void UnsignedBigInteger::multiply_without_allocation(
|
||||
const UnsignedBigInteger& left,
|
||||
const UnsignedBigInteger& right,
|
||||
UnsignedBigInteger& temp_shift_result,
|
||||
UnsignedBigInteger& temp_shift_plus,
|
||||
UnsignedBigInteger& temp_shift,
|
||||
UnsignedBigInteger& temp_plus,
|
||||
UnsignedBigInteger& output)
|
||||
{
|
||||
output.set_to_0();
|
||||
|
||||
// iterate all bits
|
||||
for (size_t word_index = 0; word_index < left.length(); ++word_index) {
|
||||
for (size_t bit_index = 0; bit_index < UnsignedBigInteger::BITS_IN_WORD; ++bit_index) {
|
||||
// If the bit is off - skip over it
|
||||
if (!(left.m_words[word_index] & (1 << bit_index)))
|
||||
continue;
|
||||
|
||||
const size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
|
||||
|
||||
// output += (right << shift_amount);
|
||||
shift_left_without_allocation(right, shift_amount, temp_shift_result, temp_shift_plus, temp_shift);
|
||||
add_without_allocation(output, temp_shift, temp_plus);
|
||||
output.set_to(temp_plus);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Complexity: O(N^2) where N is the number of words in the larger number
|
||||
* Division method:
|
||||
* We loop over the bits of the divisor, attempting to subtract divisor<<i from the dividend.
|
||||
* If the result is non-negative, it means that divisor*2^i "fits" in the dividend,
|
||||
* so we set the ith bit in the quotient and reduce divisor<<i from the dividend.
|
||||
* When we're done, what's left from the dividend is the remainder.
|
||||
*/
|
||||
FLATTEN void UnsignedBigInteger::divide_without_allocation(
|
||||
const UnsignedBigInteger& numerator,
|
||||
const UnsignedBigInteger& denominator,
|
||||
UnsignedBigInteger& temp_shift_result,
|
||||
UnsignedBigInteger& temp_shift_plus,
|
||||
UnsignedBigInteger& temp_shift,
|
||||
UnsignedBigInteger& temp_minus,
|
||||
UnsignedBigInteger& quotient,
|
||||
UnsignedBigInteger& remainder)
|
||||
{
|
||||
quotient.set_to_0();
|
||||
remainder.set_to(numerator);
|
||||
|
||||
// iterate all bits
|
||||
for (int word_index = numerator.trimmed_length() - 1; word_index >= 0; --word_index) {
|
||||
for (int bit_index = UnsignedBigInteger::BITS_IN_WORD - 1; bit_index >= 0; --bit_index) {
|
||||
const size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
|
||||
shift_left_without_allocation(denominator, shift_amount, temp_shift_result, temp_shift_plus, temp_shift);
|
||||
|
||||
subtract_without_allocation(remainder, temp_shift, temp_minus);
|
||||
if (!temp_minus.is_invalid()) {
|
||||
remainder.set_to(temp_minus);
|
||||
quotient.set_bit_inplace(shift_amount);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ALWAYS_INLINE void UnsignedBigInteger::shift_left_by_n_words(
|
||||
const UnsignedBigInteger& number,
|
||||
const size_t number_of_words,
|
||||
UnsignedBigInteger& output)
|
||||
{
|
||||
// shifting left by N words means just inserting N zeroes to the beginning of the words vector
|
||||
UnsignedBigInteger result;
|
||||
|
||||
result.m_words.ensure_capacity(number_of_words + length());
|
||||
output.set_to_0();
|
||||
output.m_words.ensure_capacity(number_of_words + number.length());
|
||||
|
||||
for (size_t i = 0; i < number_of_words; ++i) {
|
||||
result.m_words.unchecked_append(0);
|
||||
output.m_words.unchecked_append(0);
|
||||
}
|
||||
for (size_t i = 0; i < length(); ++i) {
|
||||
result.m_words.unchecked_append(m_words[i]);
|
||||
for (size_t i = 0; i < number.length(); ++i) {
|
||||
output.m_words.unchecked_append(number.m_words[i]);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the word at a requested index in the result of a shift operation
|
||||
*/
|
||||
ALWAYS_INLINE u32 UnsignedBigInteger::shift_left_get_one_word(const size_t num_bits, const size_t result_word_index) const
|
||||
ALWAYS_INLINE u32 UnsignedBigInteger::shift_left_get_one_word(
|
||||
const UnsignedBigInteger& number,
|
||||
const size_t num_bits,
|
||||
const size_t result_word_index)
|
||||
{
|
||||
// "<= length()" (rather than length() - 1) is intentional,
|
||||
// The result inedx of length() is used when calculating the carry word
|
||||
ASSERT(result_word_index <= length());
|
||||
ASSERT(result_word_index <= number.length());
|
||||
ASSERT(num_bits <= UnsignedBigInteger::BITS_IN_WORD);
|
||||
u32 result = 0;
|
||||
|
||||
// we need to check for "num_bits != 0" since shifting right by 32 is apparently undefined behaviour!
|
||||
if (result_word_index > 0 && num_bits != 0) {
|
||||
result += m_words[result_word_index - 1] >> (UnsignedBigInteger::BITS_IN_WORD - num_bits);
|
||||
result += number.m_words[result_word_index - 1] >> (UnsignedBigInteger::BITS_IN_WORD - num_bits);
|
||||
}
|
||||
if (result_word_index < length() && num_bits < 32) {
|
||||
result += m_words[result_word_index] << num_bits;
|
||||
if (result_word_index < number.length() && num_bits < 32) {
|
||||
result += number.m_words[result_word_index] << num_bits;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -64,6 +64,8 @@ public:
|
|||
|
||||
const AK::Vector<u32, STARTING_WORD_SIZE>& words() const { return m_words; }
|
||||
|
||||
void set_to_0();
|
||||
void set_to(const UnsignedBigInteger& other);
|
||||
void invalidate() { m_is_invalid = true; }
|
||||
|
||||
bool is_invalid() const { return m_is_invalid; }
|
||||
|
@ -80,13 +82,19 @@ public:
|
|||
|
||||
void set_bit_inplace(size_t bit_index);
|
||||
|
||||
static void add_without_allocation(const UnsignedBigInteger& left, const UnsignedBigInteger& right, UnsignedBigInteger& output);
|
||||
static void subtract_without_allocation(const UnsignedBigInteger& left, const UnsignedBigInteger& right, UnsignedBigInteger& output);
|
||||
static void shift_left_without_allocation(const UnsignedBigInteger& number, size_t bits_to_shift_by, UnsignedBigInteger& temp_result, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
|
||||
static void multiply_without_allocation(const UnsignedBigInteger& left, const UnsignedBigInteger& right, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& temp_plus, UnsignedBigInteger& output);
|
||||
static void divide_without_allocation(const UnsignedBigInteger& numerator, const UnsignedBigInteger& denominator, UnsignedBigInteger& temp_shift_result, UnsignedBigInteger& temp_shift_plus, UnsignedBigInteger& temp_shift, UnsignedBigInteger& temp_minus, UnsignedBigInteger& quotient, UnsignedBigInteger& remainder);
|
||||
|
||||
bool operator==(const UnsignedBigInteger& other) const;
|
||||
bool operator!=(const UnsignedBigInteger& other) const;
|
||||
bool operator<(const UnsignedBigInteger& other) const;
|
||||
|
||||
private:
|
||||
ALWAYS_INLINE UnsignedBigInteger shift_left_by_n_words(const size_t number_of_words) const;
|
||||
ALWAYS_INLINE u32 shift_left_get_one_word(const size_t num_bits, const size_t result_word_index) const;
|
||||
ALWAYS_INLINE static void shift_left_by_n_words(const UnsignedBigInteger& number, size_t number_of_words, UnsignedBigInteger& output);
|
||||
ALWAYS_INLINE static u32 shift_left_get_one_word(const UnsignedBigInteger& number, size_t num_bits, size_t result_word_index);
|
||||
|
||||
static constexpr size_t BITS_IN_WORD = 32;
|
||||
AK::Vector<u32, STARTING_WORD_SIZE> m_words;
|
||||
|
|
Loading…
Add table
Reference in a new issue