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/zone.h" | 9 #include "vm/zone.h" |
| 10 | 10 |
| (...skipping 380 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 391 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 391 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
| 392 } | 392 } |
| 393 if (bigint.IsNegative()) { | 393 if (bigint.IsNegative()) { |
| 394 value = -value; | 394 value = -value; |
| 395 } | 395 } |
| 396 return Smi::New(value); | 396 return Smi::New(value); |
| 397 } | 397 } |
| 398 | 398 |
| 399 | 399 |
| 400 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { | 400 RawDouble* BigintOperations::ToDouble(const Bigint& bigint) { |
| 401 // TODO(floitsch/benl): This is a quick and dirty implementation to unblock | 401 if (bigint.IsZero()) { |
|
cshapiro
2012/03/07 21:49:18
This fast path should be expanded to covert values
floitsch
2012/03/20 04:06:48
Done.
| |
| 402 // other areas of the code. It does not handle all bit-twiddling correctly. | 402 return Double::New(0.0); |
| 403 const double shift_value = (1 << kDigitBitSize); | |
| 404 double value = 0.0; | |
| 405 for (int i = bigint.Length() - 1; i >= 0; i--) { | |
| 406 value *= shift_value; | |
| 407 value += static_cast<double>(bigint.GetChunkAt(i)); | |
| 408 } | 403 } |
| 404 | |
|
cshapiro
2012/03/07 21:49:18
How about an early exit here if the value is too l
floitsch
2012/03/20 04:06:48
Done.
| |
| 405 static const int kPhysicalSignificandSize = 52; | |
| 406 // The significand size has an additional hidden bit. | |
| 407 static const int kSignificandSize = kPhysicalSignificandSize + 1; | |
| 408 static const int kExponentBias = 0x3FF + kPhysicalSignificandSize; | |
| 409 static const int kMaxExponent = 0x7FF - kExponentBias; | |
| 410 static const uint64_t kOne64 = 1; | |
| 411 | |
| 412 // A double is composed of an exponent e and a significand s. Its value equals | |
| 413 // s * 2^e. The significand has 53 bits of which the first one must always be | |
| 414 // 1 (at least for then numbers we are working with here) and is therefore | |
| 415 // omitted. The physical size of the significand is thus 52 bits. | |
| 416 // The exponent has 11 bits and is biased by 0x3FF + 52. For example an | |
| 417 // exponent e = 10 is written as 0x3FF + 52 + 10 (in the 11 bits that are | |
| 418 // reserved for the exponent). | |
| 419 // When converting the given bignum to a double we have to pay attention to | |
| 420 // the rounding. In particular we have to decide which double to pick if an | |
| 421 // input lies exactly between two doubles. As usual with double operations | |
| 422 // we pick the double with an even significand in such cases. | |
| 423 // | |
| 424 // General approach of this algorithm: Get 54 bits (one more than the | |
| 425 // significand size) of the bigint. If the last bit is then 1, then (without | |
| 426 // knowledge of the remaining bits) we could have a half-way number. | |
| 427 // If the second-to-last bit is odd then we know that we have to round up: | |
| 428 // if the remaining bits are not zero then the input lies closer to the higher | |
| 429 // double. If the remaining bits are zero then we have a half-way case and | |
| 430 // we need to round up too (rounding to the even double). | |
| 431 // If the second-to-last bit is even then we need to look at the remaining | |
| 432 // bits to determine if any of them is not zero. If that's the case then the | |
| 433 // number lies closer to the next-higher double. Otherwise we round the | |
| 434 // half-way case down to even. | |
| 435 | |
| 436 uint64_t significand_bits = 0; | |
| 437 bool remaining_bits_are_zero = true; | |
| 438 intptr_t exponent = 0; | |
| 439 | |
|
cshapiro
2012/03/07 21:49:18
Why not use the ShiftRight method to extract the u
floitsch
2012/03/20 04:06:48
We could, but it seems overkill. I hope the new ve
| |
| 440 intptr_t digit_index = bigint.Length() - 1; | |
| 441 // In order to round correctly we need to look at half-way cases. Therefore we | |
| 442 // get kSignificandSize + 1 bits. If the last bit is 1 then we have to look | |
| 443 // at the remaining bits to know if we have to round up. | |
| 444 int needed_bits = kSignificandSize + 1; | |
| 445 while ((digit_index) >= 0 && (needed_bits > 0)) { | |
| 446 Chunk digit = bigint.GetChunkAt(digit_index--); | |
| 447 if (significand_bits == 0) { | |
| 448 significand_bits = digit; | |
| 449 while (digit != 0) { | |
| 450 needed_bits--; | |
| 451 digit >>= 1; | |
| 452 } | |
| 453 } else if (needed_bits >= kDigitBitSize) { | |
| 454 significand_bits <<= kDigitBitSize; | |
| 455 significand_bits |= digit; | |
| 456 needed_bits -= kDigitBitSize; | |
| 457 } else { | |
| 458 significand_bits <<= needed_bits; | |
| 459 int discarded_bits_count = kDigitBitSize - needed_bits; | |
| 460 significand_bits |= digit >> discarded_bits_count; | |
| 461 uint64_t discarded_bits_mask = (kOne64 << discarded_bits_count) - 1; | |
| 462 remaining_bits_are_zero = ((digit & discarded_bits_mask) == 0); | |
| 463 exponent = discarded_bits_count; | |
| 464 needed_bits = 0; | |
| 465 } | |
| 466 } | |
| 467 ASSERT(significand_bits != 0); | |
| 468 ASSERT(needed_bits > 0 || ((significand_bits >> kSignificandSize) == 1)); | |
| 469 | |
| 470 exponent += (digit_index + 1) * kDigitBitSize; | |
| 471 | |
| 472 if (needed_bits > 0) { | |
| 473 // The value cannot be a half-way case. Just shift the significand to the | |
| 474 // correct position and update the exponent accordingly. | |
| 475 significand_bits <<= (needed_bits - 1); | |
| 476 exponent -= (needed_bits - 1); | |
| 477 } else if ((significand_bits & 1) == 1) { | |
| 478 bool round_up = false; | |
| 479 | |
| 480 if ((significand_bits & 2) != 0 || !remaining_bits_are_zero) { | |
| 481 // Even if the remaining bits are zero we still need to round up since we | |
| 482 // want to round to even for half-way cases. | |
| 483 round_up = true; | |
| 484 } else { | |
| 485 // Could be a half-way case. See if the remaining bits are non-zero. | |
| 486 for (intptr_t i = 0; i <= digit_index; i++) { | |
| 487 if (!remaining_bits_are_zero) break; | |
| 488 remaining_bits_are_zero = (bigint.GetChunkAt(i) == 0); | |
| 489 } | |
| 490 round_up = !remaining_bits_are_zero; | |
| 491 } | |
| 492 // Remove the bit we used to determine half-way cases. | |
| 493 significand_bits >>= 1; | |
| 494 exponent++; | |
| 495 if (round_up) { | |
| 496 significand_bits += 1; | |
| 497 // It might be that we just went from 53 bits to 54 bits. | |
| 498 // Example: After adding 1 to 1FFF..FF (with 53 bits set to 1) we have | |
| 499 // 2000..00 (= 2 ^ 54). In this case we adjust the exponent and shift to | |
| 500 // the right yielding again an 53 bit significand: 1000...00 ('1' followed | |
| 501 // by 52 '0' digits). | |
| 502 if (significand_bits == (kOne64 << kSignificandSize)) { | |
| 503 significand_bits >>= 1; | |
| 504 exponent++; | |
| 505 } | |
| 506 } | |
| 507 } else { | |
| 508 // Simply round down. | |
| 509 significand_bits >>= 1; | |
| 510 exponent++; | |
| 511 } | |
| 512 | |
| 513 if (exponent >= kMaxExponent) { | |
| 514 // Infinity. | |
| 515 exponent = kMaxExponent; | |
| 516 significand_bits = 0; | |
| 517 } else { | |
| 518 // Clear the hidden bit in the significand. | |
| 519 ASSERT((significand_bits >> (kSignificandSize - 1)) == 1); | |
| 520 significand_bits &= ((kOne64 << kPhysicalSignificandSize) - 1); | |
| 521 } | |
| 522 uint64_t biased_exponent = exponent + kExponentBias; | |
| 523 uint64_t double_bits = | |
| 524 (biased_exponent << kPhysicalSignificandSize) | significand_bits; | |
| 525 | |
| 526 double value = bit_cast<double>(double_bits); | |
| 409 if (bigint.IsNegative()) { | 527 if (bigint.IsNegative()) { |
| 410 value = -value; | 528 value = -value; |
|
cshapiro
2012/03/07 21:49:18
Why not put the sign bit in when you are construct
floitsch
2012/03/20 04:06:48
It seems cleaner not to duplicate the bit_cast exp
| |
| 411 } | 529 } |
| 412 return Double::New(value); | 530 return Double::New(value); |
| 413 } | 531 } |
| 414 | 532 |
| 415 | 533 |
| 416 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { | 534 bool BigintOperations::FitsIntoMint(const Bigint& bigint) { |
| 417 intptr_t bigint_length = bigint.Length(); | 535 intptr_t bigint_length = bigint.Length(); |
| 418 if (bigint_length == 0) { | 536 if (bigint_length == 0) { |
| 419 return true; | 537 return true; |
| 420 } | 538 } |
| (...skipping 994 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 1415 int BigintOperations::CountBits(Chunk digit) { | 1533 int BigintOperations::CountBits(Chunk digit) { |
| 1416 int result = 0; | 1534 int result = 0; |
| 1417 while (digit != 0) { | 1535 while (digit != 0) { |
| 1418 digit >>= 1; | 1536 digit >>= 1; |
| 1419 result++; | 1537 result++; |
| 1420 } | 1538 } |
| 1421 return result; | 1539 return result; |
| 1422 } | 1540 } |
| 1423 | 1541 |
| 1424 } // namespace dart | 1542 } // namespace dart |
| OLD | NEW |