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/zone.h" | 10 #include "vm/zone.h" |
10 | 11 |
11 namespace dart { | 12 namespace dart { |
12 | 13 |
13 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { | 14 RawBigint* BigintOperations::NewFromSmi(const Smi& smi, Heap::Space space) { |
14 intptr_t value = smi.Value(); | 15 intptr_t value = smi.Value(); |
15 if (value == 0) { | 16 if (value == 0) { |
16 return Zero(); | 17 return Zero(); |
17 } | 18 } |
18 | 19 |
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
329 NoGCScope no_gc; | 330 NoGCScope no_gc; |
330 | 331 |
331 intptr_t length = bigint.Length(); | 332 intptr_t length = bigint.Length(); |
332 return ToHexCString(length, | 333 return ToHexCString(length, |
333 bigint.IsNegative(), | 334 bigint.IsNegative(), |
334 length ? bigint.ChunkAddr(0) : NULL, | 335 length ? bigint.ChunkAddr(0) : NULL, |
335 allocator); | 336 allocator); |
336 } | 337 } |
337 | 338 |
338 | 339 |
340 const char* BigintOperations::ToDecimalCString( | |
341 const Bigint& bigint, uword (*allocator)(intptr_t size)) { | |
342 // log10(2) ~= 0.30102999566398114. | |
343 const intptr_t kLog2Dividend = 30103; | |
344 const intptr_t kLog2Divisor = 100000; | |
345 // We remove a small constant for rounding imprecision, the \0 character and | |
346 // the negative sign. | |
347 const intptr_t kMaxAllowedDigitLength = | |
348 (kIntptrMax - 10) / kLog2Dividend / kDigitBitSize * kLog2Divisor; | |
349 | |
350 intptr_t length = bigint.Length(); | |
351 if (length >= kMaxAllowedDigitLength) { | |
352 // Use the preallocated out of memory exception to avoid calling | |
353 // into dart code or allocating any code. | |
354 Isolate* isolate = Isolate::Current(); | |
355 const Instance& exception = | |
356 Instance::Handle(isolate->object_store()->out_of_memory()); | |
357 Exceptions::Throw(exception); | |
358 UNREACHABLE(); | |
359 } | |
360 | |
361 // Approximate the size of the resulting string. We prefer overestimating | |
362 // to not allocating enough. | |
363 int64_t bit_length = length * kDigitBitSize; | |
364 ASSERT(bit_length > length); | |
365 int64_t decimal_length = (bit_length * kLog2Dividend / kLog2Divisor) + 1; | |
366 // Add one byte for the trailing \0 character. | |
367 int64_t required_size = decimal_length + 1; | |
368 if (bigint.IsNegative()) { | |
369 required_size++; | |
370 } | |
371 ASSERT(required_size == static_cast<intptr_t>(required_size)); | |
372 // We will fill the result in the inverse order and then exchange at the end. | |
373 char* result = | |
374 reinterpret_cast<char*>(allocator(static_cast<intptr_t>(required_size))); | |
375 ASSERT(result != NULL); | |
376 int result_pos = 0; | |
377 | |
378 // We divide the input into pieces of ~27 bits which can be efficiently | |
379 // handled. | |
380 const intptr_t kDivisorValue = 100000000; | |
381 const int kPowerOfTen = 8; | |
sra1
2012/04/02 20:03:29
It is funny that the constant called power-of-ten
floitsch
2012/04/03 11:20:52
done in https://chromiumcodereview.appspot.com/995
| |
382 ASSERT(pow(10, kPowerOfTen) == kDivisorValue); | |
383 ASSERT(static_cast<Chunk>(kDivisorValue) < kDigitMaxValue); | |
384 ASSERT(Smi::IsValid(kDivisorValue)); | |
385 const Bigint& divisor = Bigint::Handle(NewFromInt64(kDivisorValue)); | |
386 | |
387 // Rest contains the remaining bigint that needs to be printed. | |
388 Bigint& rest = Bigint::Handle(bigint.raw()); | |
389 Bigint& quotient = Bigint::Handle(); | |
390 Bigint& remainder = Bigint::Handle(); | |
391 while (!rest.IsZero()) { | |
392 DivideRemainder(rest, divisor, "ient, &remainder); | |
393 ASSERT(remainder.Length() == 1); | |
394 intptr_t part = static_cast<intptr_t>(remainder.GetChunkAt(0)); | |
395 for (int i = 0; i < kPowerOfTen; i++) { | |
396 result[result_pos++] = '0' + (part % 10); | |
397 part /= 10; | |
398 } | |
399 ASSERT(part == 0); | |
400 rest = quotient.raw(); | |
401 } | |
402 // Move the resulting position back until we don't have any zeroes anymore. | |
403 // This is done so that we can remove all leading zeroes. | |
404 while (result_pos > 1 && result[result_pos - 1] == '0') { | |
405 result_pos--; | |
406 } | |
407 if (bigint.IsNegative()) { | |
408 result[result_pos++] = '-'; | |
409 } | |
410 // Reverse the string. | |
411 int i = 0; | |
412 int j = result_pos - 1; | |
413 while (i < j) { | |
414 char tmp = result[i]; | |
415 result[i] = result[j]; | |
416 result[j] = tmp; | |
417 i++; | |
418 j--; | |
419 } | |
420 ASSERT(result_pos >= 0); | |
421 result[result_pos] = '\0'; | |
422 return result; | |
423 } | |
424 | |
425 | |
339 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { | 426 bool BigintOperations::FitsIntoSmi(const Bigint& bigint) { |
340 intptr_t bigint_length = bigint.Length(); | 427 intptr_t bigint_length = bigint.Length(); |
341 if (bigint_length == 0) { | 428 if (bigint_length == 0) { |
342 return true; | 429 return true; |
343 } | 430 } |
344 if ((bigint_length == 1) && | 431 if ((bigint_length == 1) && |
345 (static_cast<size_t>(kDigitBitSize) < | 432 (static_cast<size_t>(kDigitBitSize) < |
346 (sizeof(intptr_t) * kBitsPerByte))) { | 433 (sizeof(intptr_t) * kBitsPerByte))) { |
347 return true; | 434 return true; |
348 } | 435 } |
(...skipping 1066 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1415 int BigintOperations::CountBits(Chunk digit) { | 1502 int BigintOperations::CountBits(Chunk digit) { |
1416 int result = 0; | 1503 int result = 0; |
1417 while (digit != 0) { | 1504 while (digit != 0) { |
1418 digit >>= 1; | 1505 digit >>= 1; |
1419 result++; | 1506 result++; |
1420 } | 1507 } |
1421 return result; | 1508 return result; |
1422 } | 1509 } |
1423 | 1510 |
1424 } // namespace dart | 1511 } // namespace dart |
OLD | NEW |