Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2012 Google Inc. All Rights Reserved. | 1 // Copyright 2012 Google Inc. All Rights Reserved. |
| 2 | 2 |
| 3 #include "vm/bigint_operations.h" | 3 #include "vm/bigint_operations.h" |
| 4 | 4 |
| 5 #include "platform/utils.h" | 5 #include "platform/utils.h" |
| 6 | 6 |
| 7 #include "vm/double_internals.h" | 7 #include "vm/double_internals.h" |
| 8 #include "vm/exceptions.h" | 8 #include "vm/exceptions.h" |
| 9 #include "vm/object_store.h" | 9 #include "vm/object_store.h" |
| 10 #include "vm/zone.h" | 10 #include "vm/zone.h" |
| (...skipping 703 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 714 } | 714 } |
| 715 | 715 |
| 716 // Comba multiplication: compute each column separately. | 716 // Comba multiplication: compute each column separately. |
| 717 // Example: r = a2a1a0 * b2b1b0. | 717 // Example: r = a2a1a0 * b2b1b0. |
| 718 // r = 1 * a0b0 + | 718 // r = 1 * a0b0 + |
| 719 // 10 * (a1b0 + a0b1) + | 719 // 10 * (a1b0 + a0b1) + |
| 720 // 100 * (a2b0 + a1b1 + a0b2) + | 720 // 100 * (a2b0 + a1b1 + a0b2) + |
| 721 // 1000 * (a2b1 + a1b2) + | 721 // 1000 * (a2b1 + a1b2) + |
| 722 // 10000 * a2b2 | 722 // 10000 * a2b2 |
| 723 // | 723 // |
| 724 // Each column will be accumulated in an integer of type DoubleChunk. We | 724 // Each column will be accumulated in an integer of type DoubleChunk. We must |
| 725 // must guarantee that the column-sum will not overflow. | 725 // guarantee that the column-sum will not overflow. We achieve this by |
| 726 // 'blocking' the sum into overflow-free sums followed by propagating the | |
| 727 // overflow. | |
| 726 // | 728 // |
| 727 // In the worst case we have to accumulate k = Min(a.length, b.length) | 729 // In the worst case we have to accumulate k = Min(a.length, b.length) |
| 728 // products plus the carry from the previous round. | 730 // products plus the carry from the previous round. |
| 729 // Each bigint-digit is smaller than beta = 2^kDigitBitSize. | 731 // Each bigint-digit is smaller than beta = 2^kDigitBitSize. |
| 730 // Each product is at most (beta - 1)^2. | 732 // Each product is at most (beta - 1)^2. |
| 731 // If we want to use Comba multiplication the following condition must hold: | 733 |
| 734 // If we want to use Comba multiplication and accumulate into a single | |
| 735 // register without overflow, the following condition must hold: | |
| 732 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) < | 736 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) < |
| 733 // 2^kDoubleChunkBitSize. | 737 // 2^kDoubleChunkBitSize. |
| 738 // Solving this give the maximum number of digits that can be summed in | |
| 739 // between handling the overflow. | |
| 734 const DoubleChunk square = | 740 const DoubleChunk square = |
| 735 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue; | 741 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue; |
|
Ivan Posva
2013/08/30 21:28:13
If I understand this correctly then the values for
| |
| 736 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1); | 742 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1); |
|
Ivan Posva
2013/08/30 21:28:13
kDoubleChunkMaxValue = 0xFFFFFFFFFFFFFFFF
| |
| 737 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize; | 743 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize; |
|
Ivan Posva
2013/08/30 21:28:13
left_over_carry = 0x0000000FFFFFFFFF
| |
| 738 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square; | 744 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square; |
|
Ivan Posva
2013/08/30 21:28:13
kMaxDigits = 0xFFFFFFF000000000 / 0xFFFFFFE0000001
| |
| 739 if (Utils::Minimum(a_length, b_length) > kMaxDigits) { | 745 const intptr_t kBlockSize = kMaxDigits - 1; // -1 for incomming carry. |
| 740 // Use the preallocated out of memory exception to avoid calling | |
| 741 // into dart code or allocating any code. | |
| 742 Isolate* isolate = Isolate::Current(); | |
| 743 const Instance& exception = | |
| 744 Instance::Handle(isolate->object_store()->out_of_memory()); | |
| 745 Exceptions::Throw(exception); | |
| 746 UNREACHABLE(); | |
| 747 } | |
| 748 | 746 |
| 749 DoubleChunk accumulator = 0; // Accumulates the result of one column. | 747 DoubleChunk accumulator = 0; // Accumulates the result of one column. |
| 748 DoubleChunk accumulator_overflow = 0; | |
| 750 for (intptr_t i = 0; i < result_length; i++) { | 749 for (intptr_t i = 0; i < result_length; i++) { |
| 751 // Example: r = a2a1a0 * b2b1b0. | 750 // Example: r = a2a1a0 * b2b1b0. |
| 752 // For i == 0, compute a0b0. | 751 // For i == 0, compute a0b0. |
| 753 // i == 1, a1b0 + a0b1 + overflow from i == 0. | 752 // i == 1, a1b0 + a0b1 + overflow from i == 0. |
| 754 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1. | 753 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1. |
| 755 // ... | 754 // ... |
| 756 // The indices into a and b are such that their sum equals i. | 755 // The indices into a and b are such that their sum equals i. |
| 757 intptr_t a_index = Utils::Minimum(a_length - 1, i); | 756 intptr_t a_index = Utils::Minimum(a_length - 1, i); |
| 758 intptr_t b_index = i - a_index; | 757 intptr_t b_index = i - a_index; |
| 759 ASSERT(a_index + b_index == i); | 758 ASSERT(a_index + b_index == i); |
| 760 | 759 |
| 761 // Instead of testing for a_index >= 0 && b_index < b_length we compute the | 760 // Instead of testing for a_index >= 0 && b_index < b_length we compute the |
| 762 // number of iterations first. | 761 // number of iterations first. |
| 763 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1); | 762 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1); |
| 764 for (intptr_t j = 0; j < iterations; j++) { | 763 |
| 765 DoubleChunk chunk_a = a.GetChunkAt(a_index); | 764 // For large products we need extra bit for the overflow. The sum is broken |
| 766 DoubleChunk chunk_b = b.GetChunkAt(b_index); | 765 // into blocks to avoid dealing with the overflow on each iteration. |
| 767 accumulator += chunk_a * chunk_b; | 766 for (intptr_t j_block = 0; j_block < iterations; j_block += kBlockSize) { |
| 768 a_index--; | 767 intptr_t j_end = Utils::Minimum(j_block + kBlockSize, iterations); |
| 769 b_index++; | 768 for (intptr_t j = j_block; j < j_end; j++) { |
| 769 DoubleChunk chunk_a = a.GetChunkAt(a_index); | |
| 770 DoubleChunk chunk_b = b.GetChunkAt(b_index); | |
| 771 accumulator += chunk_a * chunk_b; | |
| 772 a_index--; | |
| 773 b_index++; | |
| 774 } | |
| 775 accumulator_overflow += (accumulator >> kDigitBitSize); | |
| 776 accumulator &= kDigitMask; | |
| 770 } | 777 } |
| 771 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask)); | 778 result.SetChunkAt(i, static_cast<Chunk>(accumulator)); |
| 772 accumulator >>= kDigitBitSize; | 779 // Overflow becomes the initial accumulator for the next column. |
| 780 accumulator = accumulator_overflow & kDigitMask; | |
| 781 // And the overflow from the overflow becomes the new overflow. This is | |
| 782 // unlikely to be non-zero since it implies a single column sum with | |
| 783 // 2^(kMaxDigits + kDigitBitSize) elements. | |
|
Ivan Posva
2013/08/30 21:28:13
That description is a bit abstract to me. But fill
| |
| 784 accumulator_overflow = (accumulator_overflow >> kDigitBitSize); | |
| 773 } | 785 } |
| 774 ASSERT(accumulator == 0); | 786 ASSERT(accumulator == 0); |
| 787 ASSERT(accumulator_overflow == 0); | |
| 775 | 788 |
| 776 Clamp(result); | 789 Clamp(result); |
| 777 return result.raw(); | 790 return result.raw(); |
| 778 } | 791 } |
| 779 | 792 |
| 780 | 793 |
| 781 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { | 794 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { |
| 782 Bigint& quotient = Bigint::Handle(); | 795 Bigint& quotient = Bigint::Handle(); |
| 783 Bigint& remainder = Bigint::Handle(); | 796 Bigint& remainder = Bigint::Handle(); |
| 784 DivideRemainder(a, b, "ient, &remainder); | 797 DivideRemainder(a, b, "ient, &remainder); |
| (...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1672 int BigintOperations::CountBits(Chunk digit) { | 1685 int BigintOperations::CountBits(Chunk digit) { |
| 1673 int result = 0; | 1686 int result = 0; |
| 1674 while (digit != 0) { | 1687 while (digit != 0) { |
| 1675 digit >>= 1; | 1688 digit >>= 1; |
| 1676 result++; | 1689 result++; |
| 1677 } | 1690 } |
| 1678 return result; | 1691 return result; |
| 1679 } | 1692 } |
| 1680 | 1693 |
| 1681 } // namespace dart | 1694 } // namespace dart |
| OLD | NEW |