Division.cpp 3.2 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283
  1. /*
  2. * Copyright (c) 2020, Itamar S. <itamar8910@gmail.com>
  3. * Copyright (c) 2020-2021, Dex♪ <dexes.ttp@gmail.com>
  4. *
  5. * SPDX-License-Identifier: BSD-2-Clause
  6. */
  7. #include "UnsignedBigIntegerAlgorithms.h"
  8. namespace Crypto {
  9. /**
  10. * Complexity: O(N^2) where N is the number of words in the larger number
  11. * Division method:
  12. * We loop over the bits of the divisor, attempting to subtract divisor<<i from the dividend.
  13. * If the result is non-negative, it means that divisor*2^i "fits" in the dividend,
  14. * so we set the ith bit in the quotient and reduce divisor<<i from the dividend.
  15. * When we're done, what's left from the dividend is the remainder.
  16. */
  17. FLATTEN void UnsignedBigIntegerAlgorithms::divide_without_allocation(
  18. UnsignedBigInteger const& numerator,
  19. UnsignedBigInteger const& denominator,
  20. UnsignedBigInteger& temp_shift_result,
  21. UnsignedBigInteger& temp_shift_plus,
  22. UnsignedBigInteger& temp_shift,
  23. UnsignedBigInteger& temp_minus,
  24. UnsignedBigInteger& quotient,
  25. UnsignedBigInteger& remainder)
  26. {
  27. quotient.set_to_0();
  28. remainder.set_to(numerator);
  29. // iterate all bits
  30. for (int word_index = numerator.trimmed_length() - 1; word_index >= 0; --word_index) {
  31. for (int bit_index = UnsignedBigInteger::BITS_IN_WORD - 1; bit_index >= 0; --bit_index) {
  32. size_t shift_amount = word_index * UnsignedBigInteger::BITS_IN_WORD + bit_index;
  33. shift_left_without_allocation(denominator, shift_amount, temp_shift_result, temp_shift_plus, temp_shift);
  34. subtract_without_allocation(remainder, temp_shift, temp_minus);
  35. if (!temp_minus.is_invalid()) {
  36. remainder.set_to(temp_minus);
  37. quotient.set_bit_inplace(shift_amount);
  38. }
  39. }
  40. }
  41. }
  42. /**
  43. * Complexity : O(N) where N is the number of digits in the numerator
  44. * Division method :
  45. * Starting from the most significant one, for each half-word of the numerator, combine it
  46. * with the existing remainder if any, divide the combined number as a u32 operation and
  47. * update the quotient / remainder as needed.
  48. */
  49. FLATTEN void UnsignedBigIntegerAlgorithms::divide_u16_without_allocation(
  50. UnsignedBigInteger const& numerator,
  51. UnsignedBigInteger::Word denominator,
  52. UnsignedBigInteger& quotient,
  53. UnsignedBigInteger& remainder)
  54. {
  55. VERIFY(denominator < (1 << 16));
  56. UnsignedBigInteger::Word remainder_word = 0;
  57. auto numerator_length = numerator.trimmed_length();
  58. quotient.set_to_0();
  59. quotient.m_words.resize(numerator_length);
  60. for (int word_index = numerator_length - 1; word_index >= 0; --word_index) {
  61. auto word_high = numerator.m_words[word_index] >> 16;
  62. auto word_low = numerator.m_words[word_index] & ((1 << 16) - 1);
  63. auto number_to_divide_high = (remainder_word << 16) | word_high;
  64. auto quotient_high = number_to_divide_high / denominator;
  65. remainder_word = number_to_divide_high % denominator;
  66. auto number_to_divide_low = remainder_word << 16 | word_low;
  67. auto quotient_low = number_to_divide_low / denominator;
  68. remainder_word = number_to_divide_low % denominator;
  69. quotient.m_words[word_index] = (quotient_high << 16) | quotient_low;
  70. }
  71. remainder.set_to(remainder_word);
  72. }
  73. }