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/assert.h" | 5 #include "platform/assert.h" |
6 #include "platform/utils.h" | 6 #include "platform/utils.h" |
7 | 7 |
8 #include "vm/double_internals.h" | 8 #include "vm/double_internals.h" |
9 #include "vm/exceptions.h" | 9 #include "vm/exceptions.h" |
10 #include "vm/object_store.h" | 10 #include "vm/object_store.h" |
(...skipping 19 matching lines...) Expand all Loading... |
30 // Count number of needed Digits. | 30 // Count number of needed Digits. |
31 intptr_t digit_count = 0; | 31 intptr_t digit_count = 0; |
32 intptr_t count_value = value; | 32 intptr_t count_value = value; |
33 while (count_value > 0) { | 33 while (count_value > 0) { |
34 digit_count++; | 34 digit_count++; |
35 count_value >>= kDigitBitSize; | 35 count_value >>= kDigitBitSize; |
36 } | 36 } |
37 | 37 |
38 // Allocate a bigint of the correct size and copy the bits. | 38 // Allocate a bigint of the correct size and copy the bits. |
39 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); | 39 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); |
40 for (int i = 0; i < digit_count; i++) { | 40 for (intptr_t i = 0; i < digit_count; i++) { |
41 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); | 41 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); |
42 value >>= kDigitBitSize; | 42 value >>= kDigitBitSize; |
43 } | 43 } |
44 result.SetSign(is_negative); | 44 result.SetSign(is_negative); |
45 ASSERT(IsClamped(result)); | 45 ASSERT(IsClamped(result)); |
46 return result.raw(); | 46 return result.raw(); |
47 } | 47 } |
48 | 48 |
49 | 49 |
50 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) { | 50 RawBigint* BigintOperations::NewFromInt64(int64_t value, Heap::Space space) { |
(...skipping 18 matching lines...) Expand all Loading... |
69 // Count number of needed Digits. | 69 // Count number of needed Digits. |
70 intptr_t digit_count = 0; | 70 intptr_t digit_count = 0; |
71 uint64_t count_value = value; | 71 uint64_t count_value = value; |
72 while (count_value > 0) { | 72 while (count_value > 0) { |
73 digit_count++; | 73 digit_count++; |
74 count_value >>= kDigitBitSize; | 74 count_value >>= kDigitBitSize; |
75 } | 75 } |
76 | 76 |
77 // Allocate a bigint of the correct size and copy the bits. | 77 // Allocate a bigint of the correct size and copy the bits. |
78 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); | 78 const Bigint& result = Bigint::Handle(Bigint::Allocate(digit_count, space)); |
79 for (int i = 0; i < digit_count; i++) { | 79 for (intptr_t i = 0; i < digit_count; i++) { |
80 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); | 80 result.SetChunkAt(i, static_cast<Chunk>(value & kDigitMask)); |
81 value >>= kDigitBitSize; | 81 value >>= kDigitBitSize; |
82 } | 82 } |
83 result.SetSign(false); | 83 result.SetSign(false); |
84 ASSERT(IsClamped(result)); | 84 ASSERT(IsClamped(result)); |
85 return result.raw(); | 85 return result.raw(); |
86 } | 86 } |
87 | 87 |
88 | 88 |
89 RawBigint* BigintOperations::NewFromCString(const char* str, | 89 RawBigint* BigintOperations::NewFromCString(const char* str, |
(...skipping 77 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
167 | 167 |
168 const intptr_t str_length = strlen(str); | 168 const intptr_t str_length = strlen(str); |
169 if (str_length < 0) { | 169 if (str_length < 0) { |
170 FATAL("Fatal error in BigintOperations::FromDecimalCString: " | 170 FATAL("Fatal error in BigintOperations::FromDecimalCString: " |
171 "string too long"); | 171 "string too long"); |
172 } | 172 } |
173 intptr_t str_pos = 0; | 173 intptr_t str_pos = 0; |
174 | 174 |
175 // Read first digit separately. This avoids a multiplication and addition. | 175 // Read first digit separately. This avoids a multiplication and addition. |
176 // The first digit might also not have kDigitsPerIteration decimal digits. | 176 // The first digit might also not have kDigitsPerIteration decimal digits. |
177 int first_digit_decimal_digits = str_length % kDigitsPerIteration; | 177 intptr_t first_digit_decimal_digits = str_length % kDigitsPerIteration; |
178 Chunk digit = 0; | 178 Chunk digit = 0; |
179 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { | 179 for (intptr_t i = 0; i < first_digit_decimal_digits; i++) { |
180 char c = str[str_pos++]; | 180 char c = str[str_pos++]; |
181 ASSERT(('0' <= c) && (c <= '9')); | 181 ASSERT(('0' <= c) && (c <= '9')); |
182 digit = digit * 10 + c - '0'; | 182 digit = digit * 10 + c - '0'; |
183 } | 183 } |
184 Bigint& result = Bigint::Handle(Bigint::Allocate(1)); | 184 Bigint& result = Bigint::Handle(Bigint::Allocate(1)); |
185 result.SetChunkAt(0, digit); | 185 result.SetChunkAt(0, digit); |
186 Clamp(result); // Multiplication requires the inputs to be clamped. | 186 Clamp(result); // Multiplication requires the inputs to be clamped. |
187 | 187 |
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
219 return NewFromSmi(zero, space); | 219 return NewFromSmi(zero, space); |
220 } | 220 } |
221 DoubleInternals internals = DoubleInternals(d); | 221 DoubleInternals internals = DoubleInternals(d); |
222 if (internals.IsSpecial()) { | 222 if (internals.IsSpecial()) { |
223 const Array& exception_arguments = Array::Handle(Array::New(1)); | 223 const Array& exception_arguments = Array::Handle(Array::New(1)); |
224 exception_arguments.SetAt( | 224 exception_arguments.SetAt( |
225 0, Object::Handle(String::New("BigintOperations::NewFromDouble"))); | 225 0, Object::Handle(String::New("BigintOperations::NewFromDouble"))); |
226 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); | 226 Exceptions::ThrowByType(Exceptions::kInternalError, exception_arguments); |
227 } | 227 } |
228 uint64_t significand = internals.Significand(); | 228 uint64_t significand = internals.Significand(); |
229 int exponent = internals.Exponent(); | 229 intptr_t exponent = internals.Exponent(); |
230 int sign = internals.Sign(); | 230 intptr_t sign = internals.Sign(); |
231 if (exponent <= 0) { | 231 if (exponent <= 0) { |
232 significand >>= -exponent; | 232 significand >>= -exponent; |
233 exponent = 0; | 233 exponent = 0; |
234 } else if (exponent <= 10) { | 234 } else if (exponent <= 10) { |
235 // A double significand has at most 53 bits. The following shift will | 235 // A double significand has at most 53 bits. The following shift will |
236 // hence not overflow, and yield an integer of at most 63 bits. | 236 // hence not overflow, and yield an integer of at most 63 bits. |
237 significand <<= exponent; | 237 significand <<= exponent; |
238 exponent = 0; | 238 exponent = 0; |
239 } | 239 } |
240 // A significand has at most 63 bits (after the shift above). | 240 // A significand has at most 63 bits (after the shift above). |
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
277 ASSERT(result != NULL); | 277 ASSERT(result != NULL); |
278 memmove(result, zero, kLength); | 278 memmove(result, zero, kLength); |
279 result[kLength] = '\0'; | 279 result[kLength] = '\0'; |
280 return result; | 280 return result; |
281 } | 281 } |
282 ASSERT(chunk_data != NULL); | 282 ASSERT(chunk_data != NULL); |
283 | 283 |
284 // Compute the number of hex-digits that are needed to represent the | 284 // Compute the number of hex-digits that are needed to represent the |
285 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit | 285 // leading bigint-digit. All other digits need exactly kHexCharsPerDigit |
286 // characters. | 286 // characters. |
287 int leading_hex_digits = 0; | 287 intptr_t leading_hex_digits = 0; |
288 Chunk leading_digit = chunk_data[chunk_length - 1]; | 288 Chunk leading_digit = chunk_data[chunk_length - 1]; |
289 while (leading_digit != 0) { | 289 while (leading_digit != 0) { |
290 leading_hex_digits++; | 290 leading_hex_digits++; |
291 leading_digit >>= 4; | 291 leading_digit >>= 4; |
292 } | 292 } |
293 // Sum up the space that is needed for the string-representation. | 293 // Sum up the space that is needed for the string-representation. |
294 intptr_t required_size = 0; | 294 intptr_t required_size = 0; |
295 if (is_negative) { | 295 if (is_negative) { |
296 required_size++; // For the leading "-". | 296 required_size++; // For the leading "-". |
297 } | 297 } |
298 required_size += 2; // For the "0x". | 298 required_size += 2; // For the "0x". |
299 required_size += leading_hex_digits; | 299 required_size += leading_hex_digits; |
300 required_size += (chunk_length - 1) * kHexCharsPerDigit; | 300 required_size += (chunk_length - 1) * kHexCharsPerDigit; |
301 required_size++; // For the trailing '\0'. | 301 required_size++; // For the trailing '\0'. |
302 char* result = reinterpret_cast<char*>(allocator(required_size)); | 302 char* result = reinterpret_cast<char*>(allocator(required_size)); |
303 // Print the number into the string. | 303 // Print the number into the string. |
304 // Start from the last position. | 304 // Start from the last position. |
305 intptr_t pos = required_size - 1; | 305 intptr_t pos = required_size - 1; |
306 result[pos--] = '\0'; | 306 result[pos--] = '\0'; |
307 for (intptr_t i = 0; i < (chunk_length - 1); i++) { | 307 for (intptr_t i = 0; i < (chunk_length - 1); i++) { |
308 // Print all non-leading characters (which are printed with | 308 // Print all non-leading characters (which are printed with |
309 // kHexCharsPerDigit characters. | 309 // kHexCharsPerDigit characters. |
310 Chunk digit = chunk_data[i]; | 310 Chunk digit = chunk_data[i]; |
311 for (int j = 0; j < kHexCharsPerDigit; j++) { | 311 for (intptr_t j = 0; j < kHexCharsPerDigit; j++) { |
312 result[pos--] = Utils::IntToHexDigit(static_cast<int>(digit & 0xF)); | 312 result[pos--] = Utils::IntToHexDigit(static_cast<int>(digit & 0xF)); |
313 digit >>= 4; | 313 digit >>= 4; |
314 } | 314 } |
315 } | 315 } |
316 // Print the leading digit. | 316 // Print the leading digit. |
317 leading_digit = chunk_data[chunk_length - 1]; | 317 leading_digit = chunk_data[chunk_length - 1]; |
318 while (leading_digit != 0) { | 318 while (leading_digit != 0) { |
319 result[pos--] = Utils::IntToHexDigit(static_cast<int>(leading_digit & 0xF)); | 319 result[pos--] = Utils::IntToHexDigit(static_cast<int>(leading_digit & 0xF)); |
320 leading_digit >>= 4; | 320 leading_digit >>= 4; |
321 } | 321 } |
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
370 // Add one byte for the trailing \0 character. | 370 // Add one byte for the trailing \0 character. |
371 int64_t required_size = decimal_length + 1; | 371 int64_t required_size = decimal_length + 1; |
372 if (bigint.IsNegative()) { | 372 if (bigint.IsNegative()) { |
373 required_size++; | 373 required_size++; |
374 } | 374 } |
375 ASSERT(required_size == static_cast<intptr_t>(required_size)); | 375 ASSERT(required_size == static_cast<intptr_t>(required_size)); |
376 // We will fill the result in the inverse order and then exchange at the end. | 376 // We will fill the result in the inverse order and then exchange at the end. |
377 char* result = | 377 char* result = |
378 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); | 378 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); |
379 ASSERT(result != NULL); | 379 ASSERT(result != NULL); |
380 int result_pos = 0; | 380 intptr_t result_pos = 0; |
381 | 381 |
382 // We divide the input into pieces of ~27 bits which can be efficiently | 382 // We divide the input into pieces of ~27 bits which can be efficiently |
383 // handled. | 383 // handled. |
384 const intptr_t kChunkDivisor = 100000000; | 384 const intptr_t kChunkDivisor = 100000000; |
385 const int kChunkDigits = 8; | 385 const int kChunkDigits = 8; |
386 ASSERT(pow(10.0, kChunkDigits) == kChunkDivisor); | 386 ASSERT(pow(10.0, kChunkDigits) == kChunkDivisor); |
387 ASSERT(static_cast<Chunk>(kChunkDivisor) < kDigitMaxValue); | 387 ASSERT(static_cast<Chunk>(kChunkDivisor) < kDigitMaxValue); |
388 ASSERT(Smi::IsValid(kChunkDivisor)); | 388 ASSERT(Smi::IsValid(kChunkDivisor)); |
389 const Chunk divisor = static_cast<Chunk>(kChunkDivisor); | 389 const Chunk divisor = static_cast<Chunk>(kChunkDivisor); |
390 | 390 |
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
437 uintptr_t limit; | 437 uintptr_t limit; |
438 if (bigint.IsNegative()) { | 438 if (bigint.IsNegative()) { |
439 limit = static_cast<uintptr_t>(-Smi::kMinValue); | 439 limit = static_cast<uintptr_t>(-Smi::kMinValue); |
440 } else { | 440 } else { |
441 limit = static_cast<uintptr_t>(Smi::kMaxValue); | 441 limit = static_cast<uintptr_t>(Smi::kMaxValue); |
442 } | 442 } |
443 bool bigint_is_greater = false; | 443 bool bigint_is_greater = false; |
444 // Consume the least-significant digits of the bigint. | 444 // Consume the least-significant digits of the bigint. |
445 // If bigint_is_greater is set, then the processed sub-part of the bigint is | 445 // If bigint_is_greater is set, then the processed sub-part of the bigint is |
446 // greater than the corresponding part of the limit. | 446 // greater than the corresponding part of the limit. |
447 for (int i = 0; i < bigint_length - 1; i++) { | 447 for (intptr_t i = 0; i < bigint_length - 1; i++) { |
448 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); | 448 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); |
449 Chunk bigint_digit = bigint.GetChunkAt(i); | 449 Chunk bigint_digit = bigint.GetChunkAt(i); |
450 if (limit_digit < bigint_digit) { | 450 if (limit_digit < bigint_digit) { |
451 bigint_is_greater = true; | 451 bigint_is_greater = true; |
452 } else if (limit_digit > bigint_digit) { | 452 } else if (limit_digit > bigint_digit) { |
453 bigint_is_greater = false; | 453 bigint_is_greater = false; |
454 } // else don't change the boolean. | 454 } // else don't change the boolean. |
455 limit >>= kDigitBitSize; | 455 limit >>= kDigitBitSize; |
456 | 456 |
457 // Bail out if the bigint is definitely too big. | 457 // Bail out if the bigint is definitely too big. |
458 if (limit == 0) { | 458 if (limit == 0) { |
459 return false; | 459 return false; |
460 } | 460 } |
461 } | 461 } |
462 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); | 462 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); |
463 if (limit > most_significant_digit) { | 463 if (limit > most_significant_digit) { |
464 return true; | 464 return true; |
465 } | 465 } |
466 if (limit < most_significant_digit) { | 466 if (limit < most_significant_digit) { |
467 return false; | 467 return false; |
468 } | 468 } |
469 return !bigint_is_greater; | 469 return !bigint_is_greater; |
470 } | 470 } |
471 | 471 |
472 | 472 |
473 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { | 473 RawSmi* BigintOperations::ToSmi(const Bigint& bigint) { |
474 ASSERT(FitsIntoSmi(bigint)); | 474 ASSERT(FitsIntoSmi(bigint)); |
475 intptr_t value = 0; | 475 intptr_t value = 0; |
476 for (int i = bigint.Length() - 1; i >= 0; i--) { | 476 for (intptr_t i = bigint.Length() - 1; i >= 0; i--) { |
477 value <<= kDigitBitSize; | 477 value <<= kDigitBitSize; |
478 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 478 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
479 } | 479 } |
480 if (bigint.IsNegative()) { | 480 if (bigint.IsNegative()) { |
481 value = -value; | 481 value = -value; |
482 } | 482 } |
483 return Smi::New(value); | 483 return Smi::New(value); |
484 } | 484 } |
485 | 485 |
486 | 486 |
(...skipping 149 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
636 uint64_t limit; | 636 uint64_t limit; |
637 if (bigint.IsNegative()) { | 637 if (bigint.IsNegative()) { |
638 limit = static_cast<uint64_t>(Mint::kMinValue); | 638 limit = static_cast<uint64_t>(Mint::kMinValue); |
639 } else { | 639 } else { |
640 limit = static_cast<uint64_t>(Mint::kMaxValue); | 640 limit = static_cast<uint64_t>(Mint::kMaxValue); |
641 } | 641 } |
642 bool bigint_is_greater = false; | 642 bool bigint_is_greater = false; |
643 // Consume the least-significant digits of the bigint. | 643 // Consume the least-significant digits of the bigint. |
644 // If bigint_is_greater is set, then the processed sub-part of the bigint is | 644 // If bigint_is_greater is set, then the processed sub-part of the bigint is |
645 // greater than the corresponding part of the limit. | 645 // greater than the corresponding part of the limit. |
646 for (int i = 0; i < bigint_length - 1; i++) { | 646 for (intptr_t i = 0; i < bigint_length - 1; i++) { |
647 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); | 647 Chunk limit_digit = static_cast<Chunk>(limit & kDigitMask); |
648 Chunk bigint_digit = bigint.GetChunkAt(i); | 648 Chunk bigint_digit = bigint.GetChunkAt(i); |
649 if (limit_digit < bigint_digit) { | 649 if (limit_digit < bigint_digit) { |
650 bigint_is_greater = true; | 650 bigint_is_greater = true; |
651 } else if (limit_digit > bigint_digit) { | 651 } else if (limit_digit > bigint_digit) { |
652 bigint_is_greater = false; | 652 bigint_is_greater = false; |
653 } // else don't change the boolean. | 653 } // else don't change the boolean. |
654 limit >>= kDigitBitSize; | 654 limit >>= kDigitBitSize; |
655 | 655 |
656 // Bail out if the bigint is definitely too big. | 656 // Bail out if the bigint is definitely too big. |
657 if (limit == 0) { | 657 if (limit == 0) { |
658 return false; | 658 return false; |
659 } | 659 } |
660 } | 660 } |
661 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); | 661 Chunk most_significant_digit = bigint.GetChunkAt(bigint_length - 1); |
662 if (limit > most_significant_digit) { | 662 if (limit > most_significant_digit) { |
663 return true; | 663 return true; |
664 } | 664 } |
665 if (limit < most_significant_digit) { | 665 if (limit < most_significant_digit) { |
666 return false; | 666 return false; |
667 } | 667 } |
668 return !bigint_is_greater; | 668 return !bigint_is_greater; |
669 } | 669 } |
670 | 670 |
671 | 671 |
672 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { | 672 uint64_t BigintOperations::AbsToUint64(const Bigint& bigint) { |
673 ASSERT(AbsFitsIntoUint64(bigint)); | 673 ASSERT(AbsFitsIntoUint64(bigint)); |
674 uint64_t value = 0; | 674 uint64_t value = 0; |
675 for (int i = bigint.Length() - 1; i >= 0; i--) { | 675 for (intptr_t i = bigint.Length() - 1; i >= 0; i--) { |
676 value <<= kDigitBitSize; | 676 value <<= kDigitBitSize; |
677 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); | 677 value += static_cast<intptr_t>(bigint.GetChunkAt(i)); |
678 } | 678 } |
679 return value; | 679 return value; |
680 } | 680 } |
681 | 681 |
682 | 682 |
683 int64_t BigintOperations::ToInt64(const Bigint& bigint) { | 683 int64_t BigintOperations::ToInt64(const Bigint& bigint) { |
684 if (bigint.IsZero()) { | 684 if (bigint.IsZero()) { |
685 return 0; | 685 return 0; |
686 } | 686 } |
687 ASSERT(FitsIntoInt64(bigint)); | 687 ASSERT(FitsIntoInt64(bigint)); |
688 int64_t value = AbsToUint64(bigint); | 688 int64_t value = AbsToUint64(bigint); |
689 if (bigint.IsNegative()) { | 689 if (bigint.IsNegative()) { |
690 value = -value; | 690 value = -value; |
691 } | 691 } |
692 return value; | 692 return value; |
693 } | 693 } |
694 | 694 |
695 | 695 |
696 bool BigintOperations::AbsFitsIntoUint64(const Bigint& bigint) { | 696 bool BigintOperations::AbsFitsIntoUint64(const Bigint& bigint) { |
697 intptr_t b_length = bigint.Length(); | 697 intptr_t b_length = bigint.Length(); |
698 int num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); | 698 intptr_t num_bits = CountBits(bigint.GetChunkAt(b_length - 1)); |
699 num_bits += (kDigitBitSize * (b_length - 1)); | 699 num_bits += (kDigitBitSize * (b_length - 1)); |
700 if (num_bits > 64) return false; | 700 if (num_bits > 64) return false; |
701 return true; | 701 return true; |
702 } | 702 } |
703 | 703 |
704 | 704 |
705 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { | 705 bool BigintOperations::FitsIntoUint64(const Bigint& bigint) { |
706 if (bigint.IsNegative()) return false; | 706 if (bigint.IsNegative()) return false; |
707 return AbsFitsIntoUint64(bigint); | 707 return AbsFitsIntoUint64(bigint); |
708 } | 708 } |
(...skipping 1079 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1788 intptr_t bigint_length = bigint.Length(); | 1788 intptr_t bigint_length = bigint.Length(); |
1789 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length)); | 1789 Bigint& copy = Bigint::Handle(Bigint::Allocate(bigint_length)); |
1790 for (intptr_t i = 0; i < bigint_length; i++) { | 1790 for (intptr_t i = 0; i < bigint_length; i++) { |
1791 copy.SetChunkAt(i, bigint.GetChunkAt(i)); | 1791 copy.SetChunkAt(i, bigint.GetChunkAt(i)); |
1792 } | 1792 } |
1793 copy.SetSign(bigint.IsNegative()); | 1793 copy.SetSign(bigint.IsNegative()); |
1794 return copy.raw(); | 1794 return copy.raw(); |
1795 } | 1795 } |
1796 | 1796 |
1797 | 1797 |
1798 int BigintOperations::CountBits(Chunk digit) { | 1798 intptr_t BigintOperations::CountBits(Chunk digit) { |
1799 int result = 0; | 1799 intptr_t result = 0; |
1800 while (digit != 0) { | 1800 while (digit != 0) { |
1801 digit >>= 1; | 1801 digit >>= 1; |
1802 result++; | 1802 result++; |
1803 } | 1803 } |
1804 return result; | 1804 return result; |
1805 } | 1805 } |
1806 | 1806 |
1807 } // namespace dart | 1807 } // namespace dart |
OLD | NEW |