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 469 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 480 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 480 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
| 481 } | 481 } |
| 482 if (bigint.IsNegative()) { | 482 if (bigint.IsNegative()) { |
| 483 value = -value; | 483 value = -value; |
| 484 } | 484 } |
| 485 return Smi::New(value); | 485 return Smi::New(value); |
| 486 } | 486 } |
| 487 | 487 |
| 488 | 488 |
| 489 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { | 489 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { |
| 490 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock | 490 ASSERT(IsClamped(bigint)); |
| 491 // other areas of the code. It does not handle all bit-twiddling correctly. | 491 if (bigint.IsZero()) { |
| 492 const double shift_value = (1 << kDigitBitSize); | 492 return Double::New(0.0); |
| 493 double value = 0.0; | |
| 494 for (int i = bigint.Length() - 1; i >= 0; i--) { | |
| 495 value *= shift_value; | |
| 496 value += static_cast<double>(bigint.GetChunkAt(i)); | |
| 497 } | 493 } |
| 494 if (AbsFitsIntoUint64(bigint)) { | |
| 495 double absolute_value = static_cast<uint64_t>(AbsToUint64(bigint)); | |
|
cshapiro
2012/03/23 00:44:39
Is the static_cast<uint64_t>(...) needed? AbsToUi
floitsch
2012/03/26 22:52:05
typo. Should have been static_cast<double>.
done.
| |
| 496 double result = bigint.IsNegative() ? -absolute_value : absolute_value; | |
| 497 return Double::New(result); | |
| 498 } | |
| 499 | |
| 500 static const int kPhysicalSignificandSize = 52; | |
| 501 // The significand size has an additional hidden bit. | |
| 502 static const int kSignificandSize = kPhysicalSignificandSize + 1; | |
| 503 static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; | |
| 504 static const int kMaxExponent = 0x7FF - kExponentBias; | |
| 505 static const uint64_t kOne64 = 1; | |
| 506 static const uint64_t kInfinityBits = | |
| 507 DART_2PART_UINT64_C(0x7FF00000, 00000000); | |
| 508 | |
| 509 // A double is composed of an exponent e and a significand s. Its value equals | |
| 510 // s * 2^e. The significand has 53 bits of which the first one must always be | |
| 511 // 1 (at least for then numbers we are working with here) and is therefore | |
| 512 // omitted. The physical size of the significand is thus 52 bits. | |
| 513 // The exponent has 11 bits and is biased by 0x3FF + 52. For example an | |
| 514 // exponent e = 10 is written as 0x3FF + 52 + 10 (in the 11 bits that are | |
| 515 // reserved for the exponent). | |
| 516 // When converting the given bignum to a double we have to pay attention to | |
| 517 // the rounding. In particular we have to decide which double to pick if an | |
| 518 // input lies exactly between two doubles. As usual with double operations | |
| 519 // we pick the double with an even significand in such cases. | |
| 520 // | |
| 521 // General approach of this algorithm: Get 54 bits (one more than the | |
| 522 // significand size) of the bigint. If the last bit is then 1, then (without | |
| 523 // knowledge of the remaining bits) we could have a half-way number. | |
| 524 // If the second-to-last bit is odd then we know that we have to round up: | |
| 525 // if the remaining bits are not zero then the input lies closer to the higher | |
| 526 // double. If the remaining bits are zero then we have a half-way case and | |
| 527 // we need to round up too (rounding to the even double). | |
| 528 // If the second-to-last bit is even then we need to look at the remaining | |
| 529 // bits to determine if any of them is not zero. If that's the case then the | |
| 530 // number lies closer to the next-higher double. Otherwise we round the | |
| 531 // half-way case down to even. | |
| 532 | |
| 533 intptr_t length = bigint.Length(); | |
| 534 if (((length - 1) * kDigitBitSize) > (kMaxExponent + kSignificandSize)) { | |
| 535 // Does not fit into a double. | |
| 536 double infinity = bit_cast<double>(kInfinityBits); | |
| 537 return Double::New(bigint.IsNegative() ? -infinity : infinity); | |
| 538 } | |
| 539 | |
| 540 | |
| 541 intptr_t digit_index = length - 1; | |
| 542 // In order to round correctly we need to look at half-way cases. Therefore we | |
| 543 // get kSignificandSize + 1 bits. If the last bit is 1 then we have to look | |
| 544 // at the remaining bits to know if we have to round up. | |
| 545 int needed_bits = kSignificandSize + 1; | |
| 546 ASSERT((kDigitBitSize < needed_bits) && (2 * kDigitBitSize >= needed_bits)); | |
| 547 uint64_t twice_significand_floor = 0; | |
|
cshapiro
2012/03/23 00:44:39
Can we fold this into line 552? There seem to be
floitsch
2012/03/26 22:52:05
done.
| |
| 548 bool remaining_bits_are_zero = true; | |
| 549 intptr_t twice_significant_exponent = 0; | |
| 550 | |
| 551 Chunk firstDigit = bigint.GetChunkAt(digit_index--); | |
| 552 twice_significand_floor = firstDigit; | |
| 553 needed_bits -= CountBits(firstDigit); | |
| 554 if (needed_bits >= kDigitBitSize) { | |
| 555 twice_significand_floor <<= kDigitBitSize; | |
| 556 twice_significand_floor |= bigint.GetChunkAt(digit_index--); | |
| 557 needed_bits -= kDigitBitSize; | |
| 558 } | |
| 559 if (needed_bits > 0) { | |
| 560 ASSERT(needed_bits <= kDigitBitSize); | |
| 561 Chunk digit = bigint.GetChunkAt(digit_index--); | |
| 562 int discarded_bits_count = kDigitBitSize - needed_bits; | |
| 563 twice_significand_floor <<= needed_bits; | |
| 564 twice_significand_floor |= digit >> discarded_bits_count; | |
| 565 uint64_t discarded_bits_mask = (kOne64 << discarded_bits_count) - 1; | |
| 566 remaining_bits_are_zero = ((digit & discarded_bits_mask) == 0); | |
| 567 twice_significant_exponent = discarded_bits_count; | |
| 568 } | |
| 569 ASSERT((twice_significand_floor >> kSignificandSize) == 1); | |
| 570 | |
| 571 twice_significant_exponent += (digit_index + 1) * kDigitBitSize; | |
| 572 | |
| 573 // We might need to round up the significand later. | |
| 574 uint64_t significand = twice_significand_floor >> 1; | |
| 575 intptr_t exponent = twice_significant_exponent + 1; | |
| 576 | |
| 577 if (exponent >= kMaxExponent) { | |
| 578 // Infinity. | |
| 579 // Does not fit into a double. | |
| 580 double infinity = bit_cast<double>(kInfinityBits); | |
| 581 return Double::New(bigint.IsNegative() ? -infinity : infinity); | |
| 582 } | |
| 583 | |
| 584 if ((twice_significand_floor & 1) == 1) { | |
| 585 bool round_up = false; | |
| 586 | |
| 587 if ((significand & 1) != 0 || !remaining_bits_are_zero) { | |
| 588 // Even if the remaining bits are zero we still need to round up since we | |
| 589 // want to round to even for half-way cases. | |
| 590 round_up = true; | |
| 591 } else { | |
| 592 // Could be a half-way case. See if the remaining bits are non-zero. | |
| 593 for (intptr_t i = 0; i <= digit_index; i++) { | |
| 594 if (!remaining_bits_are_zero) break; | |
| 595 remaining_bits_are_zero = (bigint.GetChunkAt(i) == 0); | |
| 596 } | |
| 597 round_up = !remaining_bits_are_zero; | |
| 598 } | |
| 599 | |
| 600 if (round_up) { | |
| 601 significand++; | |
| 602 // It might be that we just went from 53 bits to 54 bits. | |
| 603 // Example: After adding 1 to 1FFF..FF (with 53 bits set to 1) we have | |
| 604 // 2000..00 (= 2 ^ 54). When adding the exponent and significand together | |
| 605 // this will increase the exponent by 1 which is exactly what we want. | |
| 606 } | |
| 607 } | |
| 608 | |
| 609 ASSERT((significand >> (kSignificandSize - 1)) == 1 | |
| 610 || significand == kOne64 << kSignificandSize); | |
| 611 uint64_t biased_exponent = exponent + kExponentBias; | |
| 612 // The significand still has the hidden bit. We simply decrement the biased | |
| 613 // exponent by one instead of playing around with the significand. | |
| 614 biased_exponent--; | |
| 615 // Note that we must use the plus operator instead of bit-or. | |
| 616 uint64_t double_bits = | |
| 617 (biased_exponent << kPhysicalSignificandSize) + significand; | |
| 618 | |
| 619 double value = bit_cast<double>(double_bits); | |
| 498 if (bigint.IsNegative()) { | 620 if (bigint.IsNegative()) { |
| 499 value = -value; | 621 value = -value; |
| 500 } | 622 } |
| 501 return Double::New(value); | 623 return Double::New(value); |
| 502 } | 624 } |
| 503 | 625 |
| 504 | 626 |
| 505 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { | 627 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { |
| 506 intptr_t bigint_length = bigint.Length(); | 628 intptr_t bigint_length = bigint.Length(); |
| 507 if (bigint_length == 0) { | 629 if (bigint_length == 0) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 543 return true; | 665 return true; |
| 544 } | 666 } |
| 545 if (limit < most_significant_digit) { | 667 if (limit < most_significant_digit) { |
| 546 return false; | 668 return false; |
| 547 } | 669 } |
| 548 return !bigint_is_greater; | 670 return !bigint_is_greater; |
| 549 } | 671 } |
| 550 | 672 |
| 551 | 673 |
| 552 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { | 674 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { |
| 675 ASSERT(AbsFitsIntoUint64(bigint)); | |
| 553 uint64_t value = 0; | 676 uint64_t value = 0; |
| 554 for (int i = bigint.Length() - 1; i >= 0; i--) { | 677 for (int i = bigint.Length() - 1; i >= 0; i--) { |
| 555 value <<= kDigitBitSize; | 678 value <<= kDigitBitSize; |
| 556 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 679 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
| 557 } | 680 } |
| 558 return value; | 681 return value; |
| 559 } | 682 } |
| 560 | 683 |
| 561 | 684 |
| 562 int64_t BigintOperations::ToMint(const Bigint& bigint) { | 685 int64_t BigintOperations::ToMint(const Bigint& bigint) { |
| 563 ASSERT(FitsIntoMint(bigint)); | 686 ASSERT(FitsIntoMint(bigint)); |
| 564 int64_t value = AbsToUint64(bigint); | 687 int64_t value = AbsToUint64(bigint); |
| 565 if (bigint.IsNegative()) { | 688 if (bigint.IsNegative()) { |
| 566 value = -value; | 689 value = -value; |
| 567 } | 690 } |
| 568 return value; | 691 return value; |
| 569 } | 692 } |
| 570 | 693 |
| 571 | 694 |
| 572 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | 695 bool BigintOperations::AbsFitsIntoUint64(const Bigint& bigint) { |
| 573 if (bigint.IsNegative()) return false; | |
| 574 intptr_t b_length = bigint.Length(); | 696 intptr_t b_length = bigint.Length(); |
| 575 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); | 697 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); |
| 576 num_bits += (kDigitBitSize * (b_length - 1)); | 698 num_bits += (kDigitBitSize * (b_length - 1)); |
| 577 if (num_bits > 64) return false; | 699 if (num_bits > 64) return false; |
| 578 return true; | 700 return true; |
| 579 } | 701 } |
| 580 | 702 |
| 581 | 703 |
| 704 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | |
| 705 if (bigint.IsNegative()) return false; | |
| 706 return AbsFitsIntoUint64(bigint); | |
| 707 } | |
| 708 | |
| 709 | |
| 582 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { | 710 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { |
| 583 ASSERT(FitsIntoUint64(bigint)); | 711 ASSERT(FitsIntoUint64(bigint)); |
| 584 return AbsToUint64(bigint); | 712 return AbsToUint64(bigint); |
| 585 } | 713 } |
| 586 | 714 |
| 587 | 715 |
| 588 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { | 716 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { |
| 589 ASSERT(IsClamped(a)); | 717 ASSERT(IsClamped(a)); |
| 590 ASSERT(IsClamped(b)); | 718 ASSERT(IsClamped(b)); |
| 591 | 719 |
| (...skipping 915 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1507 int BigintOperations::CountBits(Chunk digit) { | 1635 int BigintOperations::CountBits(Chunk digit) { |
| 1508 int result = 0; | 1636 int result = 0; |
| 1509 while (digit != 0) { | 1637 while (digit != 0) { |
| 1510 digit >>= 1; | 1638 digit >>= 1; |
| 1511 result++; | 1639 result++; |
| 1512 } | 1640 } |
| 1513 return result; | 1641 return result; |
| 1514 } | 1642 } |
| 1515 | 1643 |
| 1516 } // namespace dart | 1644 } // namespace dart |
| OLD | NEW |