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 318 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 NoGCScope no_gc; | 329 NoGCScope no_gc; |
330 | 330 |
331 intptr_t length = bigint.Length(); | 331 intptr_t length = bigint.Length(); |
332 return ToHexCString(length, | 332 return ToHexCString(length, |
333 bigint.IsNegative(), | 333 bigint.IsNegative(), |
334 length ? bigint.ChunkAddr(0) : NULL, | 334 length ? bigint.ChunkAddr(0) : NULL, |
335 allocator); | 335 allocator); |
336 } | 336 } |
337 | 337 |
338 | 338 |
339 const char* BigintOperations::ToDecimalCString( | |
340 const Bigint& bigint, uword (*allocator)(intptr_t size)) { | |
341 intptr_t length = bigint.Length(); | |
342 // We guard against overflows by using 64 bit computations. | |
siva
2012/03/02 19:31:45
On 64 bit machines the signed_length is actually a
floitsch
2012/03/05 14:28:17
Refactored.
| |
343 int64_t bit_length = length * kDigitBitSize; | |
344 // Approximate the size of the resulting string. We prefer overestimating | |
345 // to not allocating enough. | |
346 // log10(2) ~= 0.30102999566398114. | |
347 int64_t decimal_length = (bit_length * 30103 / 100000) + 1; | |
348 // Add one byte for the trailing \0 character. | |
349 int64_t required_size = decimal_length + 1; | |
350 if (bigint.IsNegative()) { | |
351 required_size++; | |
352 } | |
353 // TODO(floitsch): what to do if we had an overflow? | |
354 if (required_size != static_cast<intptr_t>(required_size)) { | |
siva
2012/03/02 19:31:45
I think we should assert here instead of silently
floitsch
2012/03/05 14:28:17
That's why there was a TODO. Now throwing an OOM-e
| |
355 return ""; | |
356 } | |
357 // We will fill the result in the inverse order and then exchange at the end. | |
358 char* result = | |
359 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); | |
siva
2012/03/02 19:31:45
ASSERT(result != NULL);
floitsch
2012/03/05 14:28:17
Done.
| |
360 int result_pos = 0; | |
361 | |
362 // We divide the input into pieces of ~27 bits which can be efficiently | |
363 // handled. | |
364 const intptr_t kDivisorValue = 100000000; | |
365 const int kPowerOfTen = 8; | |
366 ASSERT(pow(10, kPowerOfTen) == kDivisorValue); | |
367 ASSERT(static_cast<Chunk>(kDivisorValue) < kDigitMaxValue); | |
368 ASSERT(Smi::IsValid(kDivisorValue)); | |
369 const Smi& divisor_smi = Smi::Handle(Smi::New(kDivisorValue)); | |
370 const Bigint& divisor = Bigint::Handle(NewFromSmi(divisor_smi)); | |
371 | |
372 // Rest contains the remaining bigint that needs to be printed. | |
373 Bigint& rest = Bigint::Handle(bigint.raw()); | |
374 Bigint& quotient = Bigint::Handle(); | |
375 Bigint& remainder = Bigint::Handle(); | |
376 while (!rest.IsZero()) { | |
377 DivideRemainder(rest, divisor, "ient, &remainder); | |
378 ASSERT(remainder.Length() == 1); | |
379 intptr_t part = static_cast<intptr_t>(remainder.GetChunkAt(0)); | |
380 for (int i = 0; i < kPowerOfTen; i++) { | |
381 result[result_pos++] = '0' + part % 10; | |
siva
2012/03/02 19:31:45
'0' + (part % 10);
to make it clear for operator p
floitsch
2012/03/05 14:28:17
Done.
| |
382 part /= 10; | |
383 } | |
384 ASSERT(part == 0); | |
385 rest = quotient.raw(); | |
386 } | |
387 // Move the resulting position back until we don't have any zeroes anymore. | |
siva
2012/03/02 19:31:45
// This is done so that we can remove all leading
floitsch
2012/03/05 14:28:17
Done.
| |
388 while (result_pos > 1 && result[result_pos - 1] == '0') { | |
389 result_pos--; | |
390 } | |
391 if (bigint.IsNegative()) { | |
392 result[result_pos++] = '-'; | |
393 } | |
394 // Reverse the string. | |
395 int i = 0; | |
396 int j = result_pos - 1; | |
397 while (i < j) { | |
398 char tmp = result[i]; | |
399 result[i] = result[j]; | |
400 result[j] = tmp; | |
401 i++; | |
402 j--; | |
403 } | |
siva
2012/03/02 19:31:45
ASSERt(result_pos >= 0);
floitsch
2012/03/05 14:28:17
Done.
| |
404 result[result_pos] = '\0'; | |
405 return result; | |
406 } | |
407 | |
408 | |
339 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { | 409 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { |
340 intptr_t bigint_length = bigint.Length(); | 410 intptr_t bigint_length = bigint.Length(); |
341 if (bigint_length == 0) { | 411 if (bigint_length == 0) { |
342 return true; | 412 return true; |
343 } | 413 } |
344 if ((bigint_length == 1) && | 414 if ((bigint_length == 1) && |
345 (static_cast<size_t>(kDigitBitSize) < | 415 (static_cast<size_t>(kDigitBitSize) < |
346 (sizeof(intptr_t) * kBitsPerByte))) { | 416 (sizeof(intptr_t) * kBitsPerByte))) { |
347 return true; | 417 return true; |
348 } | 418 } |
(...skipping 1066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1415 int BigintOperations::CountBits(Chunk digit) { | 1485 int BigintOperations::CountBits(Chunk digit) { |
1416 int result = 0; | 1486 int result = 0; |
1417 while (digit != 0) { | 1487 while (digit != 0) { |
1418 digit >>= 1; | 1488 digit >>= 1; |
1419 result++; | 1489 result++; |
1420 } | 1490 } |
1421 return result; | 1491 return result; |
1422 } | 1492 } |
1423 | 1493 |
1424 } // namespace dart | 1494 } // namespace dart |
OLD | NEW |