Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(447)

Side by Side Diff: runtime/vm/bigint_operations.cc

Issue 23455014: Remove limit on bigint multiplication - fixes issue 12833. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 7 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | tests/corelib/big_integer_vm_test.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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 // Each bigint digit fits in kDigitBitSize bits.
728 // products plus the carry from the previous round. 730 // Each product fits in 2*kDigitBitSize bits.
729 // Each bigint-digit is smaller than beta = 2^kDigitBitSize. 731 // The accumulator is 8 * sizeof(DoubleChunk) == 2*kDigitBitSize + kCarryBits.
730 // Each product is at most (beta - 1)^2. 732 //
731 // If we want to use Comba multiplication the following condition must hold: 733 // Each time we add a product to the accumulator it could carry one bit into
732 // k * (beta - 1)^2 + (2^(kDoubleChunkBitSize - kDigitBitSize) - 1) < 734 // the carry bits, supporting kBlockSize = 2^kCarryBits - 1 addition
733 // 2^kDoubleChunkBitSize. 735 // operations before the DoubleChunk overflows.
734 const DoubleChunk square = 736 //
735 static_cast<DoubleChunk>(kDigitMaxValue) * kDigitMaxValue; 737 // At the end of the column sum and after each batch of kBlockSize additions
736 const DoubleChunk kDoubleChunkMaxValue = static_cast<DoubleChunk>(-1); 738 // the high kCarryBits+kDigitBitSize of accumulator are flushed to
737 const DoubleChunk left_over_carry = kDoubleChunkMaxValue >> kDigitBitSize; 739 // accumulator_overflow.
738 const intptr_t kMaxDigits = (kDoubleChunkMaxValue - left_over_carry) / square; 740 //
739 if (Utils::Minimum(a_length, b_length) > kMaxDigits) { 741 // Diagramatically, using one char per 4 bits:
740 // Use the preallocated out of memory exception to avoid calling 742 //
741 // into dart code or allocating any code. 743 // 0aaaaaaa * 0bbbbbbb -> 00pppppppppppppp product of 2 digits
742 Isolate* isolate = Isolate::Current(); 744 // |
743 const Instance& exception = 745 // + ...added to
744 Instance::Handle(isolate->object_store()->out_of_memory()); 746 // v
745 Exceptions::Throw(exception); 747 // ccSSSSSSSsssssss accumulator
746 UNREACHABLE(); 748 // ...flushed to
747 } 749 // 000000000sssssss accumulator
750 // vvvvvvvvvVVVVVVV accumulator_overflow
751 //
752 // 'sssssss' becomes the column sum an overflow is carried to next column:
753 //
754 // 000000000VVVVVVV accumulator
755 // 0000000vvvvvvvvv accumulator_overflow
756 //
757 // accumulator_overflow supports 2^(kDigitBitSize + kCarryBits) additions of
758 // products.
759 //
760 // Since the bottom (kDigitBitSize + kCarryBits) bits of accumulator_overflow
761 // are initialized from the previous column, that uses up the capacity to
762 // absorb 2^kCarryBits additions. The accumulator_overflow can overflow if
763 // the column has more than 2^(kDigitBitSize + kCarryBits) - 2^kCarryBits
764 // elements With current configuration that is 2^36-2^8 elements. That is too
765 // high to happen in practice. Comba multiplication is O(N^2) so overflow
766 // won't happen during a human lifespan.
767
768 const intptr_t kCarryBits = 8 * sizeof(DoubleChunk) - 2 * kDigitBitSize;
769 const intptr_t kBlockSize = (1 << kCarryBits) - 1;
748 770
749 DoubleChunk accumulator = 0; // Accumulates the result of one column. 771 DoubleChunk accumulator = 0; // Accumulates the result of one column.
772 DoubleChunk accumulator_overflow = 0;
750 for (intptr_t i = 0; i < result_length; i++) { 773 for (intptr_t i = 0; i < result_length; i++) {
751 // Example: r = a2a1a0 * b2b1b0. 774 // Example: r = a2a1a0 * b2b1b0.
752 // For i == 0, compute a0b0. 775 // For i == 0, compute a0b0.
753 // i == 1, a1b0 + a0b1 + overflow from i == 0. 776 // i == 1, a1b0 + a0b1 + overflow from i == 0.
754 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1. 777 // i == 2, a2b0 + a1b1 + a0b2 + overflow from i == 1.
755 // ... 778 // ...
756 // The indices into a and b are such that their sum equals i. 779 // The indices into a and b are such that their sum equals i.
757 intptr_t a_index = Utils::Minimum(a_length - 1, i); 780 intptr_t a_index = Utils::Minimum(a_length - 1, i);
758 intptr_t b_index = i - a_index; 781 intptr_t b_index = i - a_index;
759 ASSERT(a_index + b_index == i); 782 ASSERT(a_index + b_index == i);
760 783
761 // Instead of testing for a_index >= 0 && b_index < b_length we compute the 784 // Instead of testing for a_index >= 0 && b_index < b_length we compute the
762 // number of iterations first. 785 // number of iterations first.
763 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1); 786 intptr_t iterations = Utils::Minimum(b_length - b_index, a_index + 1);
764 for (intptr_t j = 0; j < iterations; j++) { 787
765 DoubleChunk chunk_a = a.GetChunkAt(a_index); 788 // For large products we need extra bit for the overflow. The sum is broken
766 DoubleChunk chunk_b = b.GetChunkAt(b_index); 789 // into blocks to avoid dealing with the overflow on each iteration.
767 accumulator += chunk_a * chunk_b; 790 for (intptr_t j_block = 0; j_block < iterations; j_block += kBlockSize) {
768 a_index--; 791 intptr_t j_end = Utils::Minimum(j_block + kBlockSize, iterations);
769 b_index++; 792 for (intptr_t j = j_block; j < j_end; j++) {
793 DoubleChunk chunk_a = a.GetChunkAt(a_index);
794 DoubleChunk chunk_b = b.GetChunkAt(b_index);
795 accumulator += chunk_a * chunk_b;
796 a_index--;
797 b_index++;
798 }
799 accumulator_overflow += (accumulator >> kDigitBitSize);
800 accumulator &= kDigitMask;
770 } 801 }
771 result.SetChunkAt(i, static_cast<Chunk>(accumulator & kDigitMask)); 802 result.SetChunkAt(i, static_cast<Chunk>(accumulator));
772 accumulator >>= kDigitBitSize; 803 // Overflow becomes the initial accumulator for the next column.
804 accumulator = accumulator_overflow & kDigitMask;
805 // And the overflow from the overflow becomes the new overflow.
806 accumulator_overflow = (accumulator_overflow >> kDigitBitSize);
773 } 807 }
774 ASSERT(accumulator == 0); 808 ASSERT(accumulator == 0);
809 ASSERT(accumulator_overflow == 0);
775 810
776 Clamp(result); 811 Clamp(result);
777 return result.raw(); 812 return result.raw();
778 } 813 }
779 814
780 815
781 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) { 816 RawBigint* BigintOperations::Divide(const Bigint& a, const Bigint& b) {
782 Bigint& quotient = Bigint::Handle(); 817 Bigint& quotient = Bigint::Handle();
783 Bigint& remainder = Bigint::Handle(); 818 Bigint& remainder = Bigint::Handle();
784 DivideRemainder(a, b, &quotient, &remainder); 819 DivideRemainder(a, b, &quotient, &remainder);
(...skipping 887 matching lines...) Expand 10 before | Expand all | Expand 10 after
1672 int BigintOperations::CountBits(Chunk digit) { 1707 int BigintOperations::CountBits(Chunk digit) {
1673 int result = 0; 1708 int result = 0;
1674 while (digit != 0) { 1709 while (digit != 0) {
1675 digit >>= 1; 1710 digit >>= 1;
1676 result++; 1711 result++;
1677 } 1712 }
1678 return result; 1713 return result;
1679 } 1714 }
1680 1715
1681 } // namespace dart 1716 } // namespace dart
OLDNEW
« no previous file with comments | « no previous file | tests/corelib/big_integer_vm_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698