| 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 447 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 458 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 458 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
| 459 } | 459 } |
| 460 if (bigint.IsNegative()) { | 460 if (bigint.IsNegative()) { |
| 461 value = -value; | 461 value = -value; |
| 462 } | 462 } |
| 463 return Smi::New(value); | 463 return Smi::New(value); |
| 464 } | 464 } |
| 465 | 465 |
| 466 | 466 |
| 467 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { | 467 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { |
| 468 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock | 468 ASSERT(IsClamped(bigint)); |
| 469 // other areas of the code. It does not handle all bit-twiddling correctly. | 469 if (bigint.IsZero()) { |
| 470 const double shift_value = (1 << kDigitBitSize); | 470 return Double::New(0.0); |
| 471 double value = 0.0; | |
| 472 for (int i = bigint.Length() - 1; i >= 0; i--) { | |
| 473 value *= shift_value; | |
| 474 value += static_cast<double>(bigint.GetChunkAt(i)); | |
| 475 } | 471 } |
| 472 if (AbsFitsIntoUint64(bigint)) { |
| 473 double absolute_value = static_cast<double>(AbsToUint64(bigint)); |
| 474 double result = bigint.IsNegative() ? -absolute_value : absolute_value; |
| 475 return Double::New(result); |
| 476 } |
| 477 |
| 478 static const int kPhysicalSignificandSize = 52; |
| 479 // The significand size has an additional hidden bit. |
| 480 static const int kSignificandSize = kPhysicalSignificandSize + 1; |
| 481 static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; |
| 482 static const int kMaxExponent = 0x7FF - kExponentBias; |
| 483 static const uint64_t kOne64 = 1; |
| 484 static const uint64_t kInfinityBits = |
| 485 DART_2PART_UINT64_C(0x7FF00000, 00000000); |
| 486 |
| 487 // A double is composed of an exponent e and a significand s. Its value equals |
| 488 // s * 2^e. The significand has 53 bits of which the first one must always be |
| 489 // 1 (at least for then numbers we are working with here) and is therefore |
| 490 // omitted. The physical size of the significand is thus 52 bits. |
| 491 // The exponent has 11 bits and is biased by 0x3FF + 52. For example an |
| 492 // exponent e = 10 is written as 0x3FF + 52 + 10 (in the 11 bits that are |
| 493 // reserved for the exponent). |
| 494 // When converting the given bignum to a double we have to pay attention to |
| 495 // the rounding. In particular we have to decide which double to pick if an |
| 496 // input lies exactly between two doubles. As usual with double operations |
| 497 // we pick the double with an even significand in such cases. |
| 498 // |
| 499 // General approach of this algorithm: Get 54 bits (one more than the |
| 500 // significand size) of the bigint. If the last bit is then 1, then (without |
| 501 // knowledge of the remaining bits) we could have a half-way number. |
| 502 // If the second-to-last bit is odd then we know that we have to round up: |
| 503 // if the remaining bits are not zero then the input lies closer to the higher |
| 504 // double. If the remaining bits are zero then we have a half-way case and |
| 505 // we need to round up too (rounding to the even double). |
| 506 // If the second-to-last bit is even then we need to look at the remaining |
| 507 // bits to determine if any of them is not zero. If that's the case then the |
| 508 // number lies closer to the next-higher double. Otherwise we round the |
| 509 // half-way case down to even. |
| 510 |
| 511 intptr_t length = bigint.Length(); |
| 512 if (((length - 1) * kDigitBitSize) > (kMaxExponent + kSignificandSize)) { |
| 513 // Does not fit into a double. |
| 514 double infinity = bit_cast<double>(kInfinityBits); |
| 515 return Double::New(bigint.IsNegative() ? -infinity : infinity); |
| 516 } |
| 517 |
| 518 |
| 519 intptr_t digit_index = length - 1; |
| 520 // In order to round correctly we need to look at half-way cases. Therefore we |
| 521 // get kSignificandSize + 1 bits. If the last bit is 1 then we have to look |
| 522 // at the remaining bits to know if we have to round up. |
| 523 int needed_bits = kSignificandSize + 1; |
| 524 ASSERT((kDigitBitSize < needed_bits) && (2 * kDigitBitSize >= needed_bits)); |
| 525 bool discarded_bits_were_zero = true; |
| 526 |
| 527 Chunk firstDigit = bigint.GetChunkAt(digit_index--); |
| 528 uint64_t twice_significand_floor = firstDigit; |
| 529 intptr_t twice_significant_exponent = (digit_index + 1) * kDigitBitSize; |
| 530 needed_bits -= CountBits(firstDigit); |
| 531 |
| 532 if (needed_bits >= kDigitBitSize) { |
| 533 twice_significand_floor <<= kDigitBitSize; |
| 534 twice_significand_floor |= bigint.GetChunkAt(digit_index--); |
| 535 twice_significant_exponent -= kDigitBitSize; |
| 536 needed_bits -= kDigitBitSize; |
| 537 } |
| 538 if (needed_bits > 0) { |
| 539 ASSERT(needed_bits <= kDigitBitSize); |
| 540 Chunk digit = bigint.GetChunkAt(digit_index--); |
| 541 int discarded_bits_count = kDigitBitSize - needed_bits; |
| 542 twice_significand_floor <<= needed_bits; |
| 543 twice_significand_floor |= digit >> discarded_bits_count; |
| 544 twice_significant_exponent -= needed_bits; |
| 545 uint64_t discarded_bits_mask = (kOne64 << discarded_bits_count) - 1; |
| 546 discarded_bits_were_zero = ((digit & discarded_bits_mask) == 0); |
| 547 } |
| 548 ASSERT((twice_significand_floor >> kSignificandSize) == 1); |
| 549 |
| 550 // We might need to round up the significand later. |
| 551 uint64_t significand = twice_significand_floor >> 1; |
| 552 intptr_t exponent = twice_significant_exponent + 1; |
| 553 |
| 554 if (exponent >= kMaxExponent) { |
| 555 // Infinity. |
| 556 // Does not fit into a double. |
| 557 double infinity = bit_cast<double>(kInfinityBits); |
| 558 return Double::New(bigint.IsNegative() ? -infinity : infinity); |
| 559 } |
| 560 |
| 561 if ((twice_significand_floor & 1) == 1) { |
| 562 bool round_up = false; |
| 563 |
| 564 if ((significand & 1) != 0 || !discarded_bits_were_zero) { |
| 565 // Even if the remaining bits are zero we still need to round up since we |
| 566 // want to round to even for half-way cases. |
| 567 round_up = true; |
| 568 } else { |
| 569 // Could be a half-way case. See if the remaining bits are non-zero. |
| 570 for (intptr_t i = 0; i <= digit_index; i++) { |
| 571 if (bigint.GetChunkAt(i) != 0) { |
| 572 round_up = true; |
| 573 break; |
| 574 } |
| 575 } |
| 576 } |
| 577 |
| 578 if (round_up) { |
| 579 significand++; |
| 580 // It might be that we just went from 53 bits to 54 bits. |
| 581 // Example: After adding 1 to 1FFF..FF (with 53 bits set to 1) we have |
| 582 // 2000..00 (= 2 ^ 54). When adding the exponent and significand together |
| 583 // this will increase the exponent by 1 which is exactly what we want. |
| 584 } |
| 585 } |
| 586 |
| 587 ASSERT((significand >> (kSignificandSize - 1)) == 1 |
| 588 || significand == kOne64 << kSignificandSize); |
| 589 uint64_t biased_exponent = exponent + kExponentBias; |
| 590 // The significand still has the hidden bit. We simply decrement the biased |
| 591 // exponent by one instead of playing around with the significand. |
| 592 biased_exponent--; |
| 593 // Note that we must use the plus operator instead of bit-or. |
| 594 uint64_t double_bits = |
| 595 (biased_exponent << kPhysicalSignificandSize) + significand; |
| 596 |
| 597 double value = bit_cast<double>(double_bits); |
| 476 if (bigint.IsNegative()) { | 598 if (bigint.IsNegative()) { |
| 477 value = -value; | 599 value = -value; |
| 478 } | 600 } |
| 479 return Double::New(value); | 601 return Double::New(value); |
| 480 } | 602 } |
| 481 | 603 |
| 482 | 604 |
| 483 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { | 605 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { |
| 484 intptr_t bigint_length = bigint.Length(); | 606 intptr_t bigint_length = bigint.Length(); |
| 485 if (bigint_length == 0) { | 607 if (bigint_length == 0) { |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 521 return true; | 643 return true; |
| 522 } | 644 } |
| 523 if (limit < most_significant_digit) { | 645 if (limit < most_significant_digit) { |
| 524 return false; | 646 return false; |
| 525 } | 647 } |
| 526 return !bigint_is_greater; | 648 return !bigint_is_greater; |
| 527 } | 649 } |
| 528 | 650 |
| 529 | 651 |
| 530 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { | 652 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { |
| 653 ASSERT(AbsFitsIntoUint64(bigint)); |
| 531 uint64_t value = 0; | 654 uint64_t value = 0; |
| 532 for (int i = bigint.Length() - 1; i >= 0; i--) { | 655 for (int i = bigint.Length() - 1; i >= 0; i--) { |
| 533 value <<= kDigitBitSize; | 656 value <<= kDigitBitSize; |
| 534 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 657 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
| 535 } | 658 } |
| 536 return value; | 659 return value; |
| 537 } | 660 } |
| 538 | 661 |
| 539 | 662 |
| 540 int64_t BigintOperations::ToMint(const Bigint& bigint) { | 663 int64_t BigintOperations::ToMint(const Bigint& bigint) { |
| 541 ASSERT(FitsIntoMint(bigint)); | 664 ASSERT(FitsIntoMint(bigint)); |
| 542 int64_t value = AbsToUint64(bigint); | 665 int64_t value = AbsToUint64(bigint); |
| 543 if (bigint.IsNegative()) { | 666 if (bigint.IsNegative()) { |
| 544 value = -value; | 667 value = -value; |
| 545 } | 668 } |
| 546 return value; | 669 return value; |
| 547 } | 670 } |
| 548 | 671 |
| 549 | 672 |
| 550 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | 673 bool BigintOperations::AbsFitsIntoUint64(const Bigint& bigint) { |
| 551 if (bigint.IsNegative()) return false; | |
| 552 intptr_t b_length = bigint.Length(); | 674 intptr_t b_length = bigint.Length(); |
| 553 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); | 675 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); |
| 554 num_bits += (kDigitBitSize * (b_length - 1)); | 676 num_bits += (kDigitBitSize * (b_length - 1)); |
| 555 if (num_bits > 64) return false; | 677 if (num_bits > 64) return false; |
| 556 return true; | 678 return true; |
| 557 } | 679 } |
| 558 | 680 |
| 559 | 681 |
| 682 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { |
| 683 if (bigint.IsNegative()) return false; |
| 684 return AbsFitsIntoUint64(bigint); |
| 685 } |
| 686 |
| 687 |
| 560 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { | 688 uint64_t BigintOperations::ToUint64(const Bigint& bigint) { |
| 561 ASSERT(FitsIntoUint64(bigint)); | 689 ASSERT(FitsIntoUint64(bigint)); |
| 562 return AbsToUint64(bigint); | 690 return AbsToUint64(bigint); |
| 563 } | 691 } |
| 564 | 692 |
| 565 | 693 |
| 566 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { | 694 RawBigint* BigintOperations::Multiply(const Bigint& a, const Bigint& b) { |
| 567 ASSERT(IsClamped(a)); | 695 ASSERT(IsClamped(a)); |
| 568 ASSERT(IsClamped(b)); | 696 ASSERT(IsClamped(b)); |
| 569 | 697 |
| (...skipping 947 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1517 int BigintOperations::CountBits(Chunk digit) { | 1645 int BigintOperations::CountBits(Chunk digit) { |
| 1518 int result = 0; | 1646 int result = 0; |
| 1519 while (digit != 0) { | 1647 while (digit != 0) { |
| 1520 digit >>= 1; | 1648 digit >>= 1; |
| 1521 result++; | 1649 result++; |
| 1522 } | 1650 } |
| 1523 return result; | 1651 return result; |
| 1524 } | 1652 } |
| 1525 | 1653 |
| 1526 } // namespace dart | 1654 } // namespace dart |
| OLD | NEW |