1
0
Fork 0
mirror of https://github.com/LadybirdBrowser/ladybird.git synced 2025-06-08 05:27:14 +09:00
ladybird/Libraries/LibCrypto/BigInt/Algorithms/Division.cpp
Pavel Shliak 8d13115d9a LibCrypto: Clean up #include directives
This change aims to improve the speed of incremental builds.
2024-11-21 14:08:33 +01:00

122 lines
4.2 KiB
C++

/*
* Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
* Copyright (c) 2020-2021, Dex♪ <dexes.ttp@gmail.com>
*
* SPDX-License-Identifier: BSD-2-Clause
*/
#include "UnsignedBigIntegerAlgorithms.h"
#include <AK/BigIntBase.h>
namespace Crypto {
using AK::Detail::div_mod_words;
using AK::Detail::dword;
/**
* Complexity: O(N^2) where N is the number of words in the larger number
* Division method:
* Knuth's Algorithm D, see UFixedBigIntDivision.h for more details
*/
FLATTEN void UnsignedBigIntegerAlgorithms::divide_without_allocation(
UnsignedBigInteger const& numerator,
UnsignedBigInteger const& denominator,
UnsignedBigInteger& quotient,
UnsignedBigInteger& remainder)
{
size_t dividend_len = numerator.trimmed_length();
size_t divisor_len = denominator.trimmed_length();
VERIFY(divisor_len != 0);
// Fast paths
// Division by 1
if (divisor_len == 1 && denominator.m_words[0] == 1) {
quotient.set_to(numerator);
remainder.set_to_0();
return;
}
if (dividend_len < divisor_len) {
quotient.set_to_0();
remainder.set_to(numerator);
return;
}
if (divisor_len == 1 && dividend_len == 1) {
quotient.set_to(numerator.m_words[0] / denominator.m_words[0]);
remainder.set_to(numerator.m_words[0] % denominator.m_words[0]);
return;
}
// Division by Word
if (divisor_len == 1) {
quotient.resize_with_leading_zeros(dividend_len);
remainder.resize_with_leading_zeros(1);
// FIXME: Use a "DoubleWord" to allow increasing the Word size of
// BigInt in the future
static_assert(UnsignedBigInteger::BITS_IN_WORD == 32);
auto u = dword(numerator.m_words[dividend_len - 2], numerator.m_words[dividend_len - 1]);
auto divisor = denominator.m_words[0];
auto top = u / divisor;
quotient.m_words[dividend_len - 1] = top >> UnsignedBigInteger::BITS_IN_WORD;
quotient.m_words[dividend_len - 2] = static_cast<UnsignedBigInteger::Word>(top);
auto carry = static_cast<UnsignedBigInteger::Word>(u % divisor);
for (size_t i = dividend_len - 2; i-- != 0;)
quotient.m_words[i] = div_mod_words(numerator.m_words[i], carry, divisor, carry);
remainder.m_words[0] = carry;
return;
}
// Knuth's algorithm D
auto dividend = numerator;
dividend.resize_with_leading_zeros(dividend_len + 1);
auto divisor = denominator;
quotient.resize_with_leading_zeros(dividend_len - divisor_len + 1);
remainder.resize_with_leading_zeros(divisor_len);
Ops::div_mod_internal<true>(
dividend.words_span(), divisor.words_span(),
quotient.words_span(), remainder.words_span(),
dividend_len, divisor_len);
}
/**
* Complexity : O(N) where N is the number of digits in the numerator
* Division method :
* Starting from the most significant one, for each half-word of the numerator, combine it
* with the existing remainder if any, divide the combined number as a u32 operation and
* update the quotient / remainder as needed.
*/
FLATTEN void UnsignedBigIntegerAlgorithms::divide_u16_without_allocation(
UnsignedBigInteger const& numerator,
UnsignedBigInteger::Word denominator,
UnsignedBigInteger& quotient,
UnsignedBigInteger& remainder)
{
VERIFY(denominator < (1 << 16));
UnsignedBigInteger::Word remainder_word = 0;
auto numerator_length = numerator.trimmed_length();
quotient.set_to_0();
quotient.m_words.resize(numerator_length);
for (int word_index = numerator_length - 1; word_index >= 0; --word_index) {
auto word_high = numerator.m_words[word_index] >> 16;
auto word_low = numerator.m_words[word_index] & ((1 << 16) - 1);
auto number_to_divide_high = (remainder_word << 16) | word_high;
auto quotient_high = number_to_divide_high / denominator;
remainder_word = number_to_divide_high % denominator;
auto number_to_divide_low = remainder_word << 16 | word_low;
auto quotient_low = number_to_divide_low / denominator;
remainder_word = number_to_divide_low % denominator;
quotient.m_words[word_index] = (quotient_high << 16) | quotient_low;
}
remainder.set_to(remainder_word);
}
}