Chromium Code Reviews| Index: src/bignum-dtoa.cc |
| =================================================================== |
| --- src/bignum-dtoa.cc (revision 0) |
| +++ src/bignum-dtoa.cc (revision 0) |
| @@ -0,0 +1,549 @@ |
| +// Copyright 2010 the V8 project authors. All rights reserved. |
| +// Redistribution and use in source and binary forms, with or without |
| +// modification, are permitted provided that the following conditions are |
| +// met: |
| +// |
| +// * Redistributions of source code must retain the above copyright |
| +// notice, this list of conditions and the following disclaimer. |
| +// * Redistributions in binary form must reproduce the above |
| +// copyright notice, this list of conditions and the following |
| +// disclaimer in the documentation and/or other materials provided |
| +// with the distribution. |
| +// * Neither the name of Google Inc. nor the names of its |
| +// contributors may be used to endorse or promote products derived |
| +// from this software without specific prior written permission. |
| +// |
| +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| +// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| +// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| +// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| +// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| +// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| +// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| +// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| +// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| + |
| +#include <math.h> |
| + |
| +#include "v8.h" |
| +#include "bignum-dtoa.h" |
| + |
| +#include "bignum.h" |
| +#include "double.h" |
| + |
| +namespace v8 { |
| +namespace internal { |
| + |
| +// Returns an estimation of k such that 10^(k-1) <= v < 10^k. |
|
William Hesse
2010/11/15 15:48:30
This is unclear. Explains that the input is the ex
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| +// The result might undershoot by 1 in which case 10^k <= v < 10^k+1. |
| +// Note: the same is true for v + wiggle_plus (instead of simply v) (see |
|
William Hesse
2010/11/15 15:48:30
What is wiggle_plus?
Florian Loitsch
2010/11/16 14:32:06
Changed to v+ (v's positive boundary).
|
| +// explanation below). |
| +// Examples: |
| +// EstimatePower(0) => 16 |
| +// EstimatePower(-52) => 0 |
| +// |
| +// Note: e >= 0 => EstimatedPower(e) > 0. No similar claim can be made for e<0. |
| +static int EstimatePower(int exponent) { |
| + // This function estimates log10 of v where v = f*2^e (with e == exponent). |
| + // Note that 10^floor(log10(v)) <= v, but v <= 10^ceil(log10(v)). |
| + // Note that f is bounded by its container size. Let p = 53 (the double's |
| + // significand size). Then 2^(p-1) <= f < 2^p. |
| + // |
| + // Given that log10(v) == log2(v)/log2(10) and e+(len(f)-1) is quite close |
| + // to log2(v) the function is simplified to (e+(len(f)-1)/log2(10)). |
| + // The computed number undershoots by less than 0.631 (when we compute log3 |
| + // and not log10). |
| + // |
| + // Optimization: since we only need an approximated result this computation |
| + // can be performed on 64 bit integers. On x86/x64 architecture the speedup is |
| + // not really measurable, though. |
| + // |
| + // Since we want to avoid overshooting we decrement by 1e10 so that |
| + // floating-point imprecisions don't affect us. |
| + // |
| + // Explanation for (v + wiggle_plus): the computation takes advantage of the |
|
William Hesse
2010/11/15 15:48:30
Can the wiggle stuff be put where wiggle is used?
Florian Loitsch
2010/11/16 14:32:06
Reworked comment.
|
| + // fact that 2^(p-1) <= f < 2^p. However even after adding the wiggle this |
| + // property is still true (even for denormals where the wiggle can be much |
| + // more important). |
| + |
| + const double k1Log10 = 0.30102999566398114; // 1/lg(10) |
| + |
| + // For doubles len(f) == 53 (don't forget the hidden bit). |
| + const int kSignificandSize = 53; |
| + double estimate = ceil((exponent + kSignificandSize - 1) * k1Log10 - 1e-10); |
| + return static_cast<int>(estimate); |
| +} |
| + |
| + |
| +// See comments for InitialScaledStartValues. |
| +static void InitialScaledStartValuesPositiveExponent( |
| + double v, int estimated_power, bool need_wiggles, |
| + Bignum* numerator, Bignum* denominator, |
| + Bignum* wiggle_minus, Bignum* wiggle_plus) { |
| + // A positive exponent implies a positive power. |
| + ASSERT(estimated_power >= 0); |
| + // Since the estimated_power is positive we simply multiply the denominator |
| + // by 10^estimated_power. |
| + |
| + // The common case first. We later (10 lines below) correct the values for |
| + // the special case where the boundaries are different. |
| + // denominator = 2 * 10^estimated_power; |
| + denominator->AssignPowerUInt16(10, estimated_power); |
| + denominator->ShiftLeft(1); |
| + // numerator = v * 2 (2 for the common denominator). |
| + numerator->AssignUInt64(Double(v).Significand()); |
| + numerator->ShiftLeft(Double(v).Exponent() + 1); |
| + |
| + if (need_wiggles) { |
|
William Hesse
2010/11/15 15:48:30
Call these delta_plus and delta_minus, or somethin
Florian Loitsch
2010/11/16 14:32:06
Refactored (slightly) method and comments.
|
| + // Let v = f * 2^e, then wiggle_plus = 2^e; |
| + wiggle_plus->AssignUInt16(1); |
| + wiggle_plus->ShiftLeft(Double(v).Exponent()); |
| + // Same for wiggle_minus. |
| + wiggle_minus->AssignUInt16(1); |
| + wiggle_minus->ShiftLeft(Double(v).Exponent()); |
| + |
| + // If the significand (without the hidden bit) is 0, then the lower |
| + // boundary is closer than just one ulp (unit in the last place). |
| + // There is only one exception: if the next lower number is a denormal then |
| + // the distance is 1 ulp. This cannot be the case for exponent >= 0 (but we |
| + // have to test it in the other function where exponent < 0). |
| + uint64_t v_bits = Double(v).AsUint64(); |
| + if ((v_bits & Double::kSignificandMask) == 0) { |
| + // The lower boundary is closer at half the distance of "normal" numbers. |
| + // Increase the denominator and adapt all but the wiggle_minus. |
| + denominator->ShiftLeft(1); // *2 |
| + numerator->ShiftLeft(1); // *2 |
| + wiggle_plus->ShiftLeft(1); // *2 |
| + } |
| + } |
| +} |
| + |
| + |
| +// See comments for InitialScaledStartValues |
| +static void InitialScaledStartValuesNegativeExponentPositivePower( |
| + double v, int estimated_power, bool need_wiggles, |
| + Bignum* numerator, Bignum* denominator, |
| + Bignum* wiggle_minus, Bignum* wiggle_plus) { |
| + uint64_t significand = Double(v).Significand(); |
| + int exponent = Double(v).Exponent(); |
| + // v = f * 2^e with e < 0, and with estimated_power >= 0. |
| + // This means that e is close to 0 (have a look at how estimated_power is |
| + // computed). |
| + |
| + // The common case first. We later (10 lines below) correct the values for |
| + // the special case where the boundaries are different. |
| + // denominator = 10^estimated_power * 2 * 2^-exponent (with exponent < 0) |
| + denominator->AssignPowerUInt16(10, estimated_power); |
| + denominator->ShiftLeft(1 - exponent); |
| + // numerator = 2 * significand |
| + // since v = significand * 2^exponent this is equivalent to |
| + // numerator = v * 2 / 2^-exponent |
| + numerator->AssignUInt64(significand); |
| + numerator->ShiftLeft(1); |
| + |
| + if (need_wiggles) { |
| + // Given that the denominator already includes v's exponent the wiggle |
| + // room is simply 1. |
| + wiggle_plus->AssignUInt16(1); |
| + // Same for wiggle_minus. |
| + wiggle_minus->AssignUInt16(1); |
| + |
| + // If the significand (without the hidden bit) is 0, then the lower |
| + // boundary is closer than just one ulp (unit in the last place). |
| + // There is only one exception: if the next lower number is a denormal |
| + // then the distance is 1 ulp. Since the exponent is close to zero |
| + // (otherwise estimated_power would have been negative) this cannot happen |
| + // here either. |
| + uint64_t v_bits = Double(v).AsUint64(); |
| + if ((v_bits & Double::kSignificandMask) == 0) { |
| + // The lower boundary is closer at half the distance of "normal" numbers. |
| + // Increase the denominator and adapt all but the wiggle_minus. |
| + denominator->ShiftLeft(1); // *2 |
| + numerator->ShiftLeft(1); // *2 |
| + wiggle_plus->ShiftLeft(1); // *2 |
| + } |
| + } |
| +} |
| + |
| + |
| +// See comments for InitialScaledStartValues |
| +static void InitialScaledStartValuesNegativeExponentNegativePower( |
| + double v, int estimated_power, bool need_wiggles, |
| + Bignum* numerator, Bignum* denominator, |
| + Bignum* wiggle_minus, Bignum* wiggle_plus) { |
| + const uint64_t kMinimalNormalizedExponent = |
| + V8_2PART_UINT64_C(0x00100000, 00000000); |
| + uint64_t significand = Double(v).Significand(); |
| + int exponent = Double(v).Exponent(); |
| + // Instead of multiplying the denominator with 10^estimated_power we |
| + // multiply all values (numerator and wiggles) by 10^-estimated_power. |
| + |
| + // Use numerator as temporary container for power_ten |
| + Bignum* power_ten = numerator; |
| + power_ten->AssignPowerUInt16(10, -estimated_power); |
| + |
| + // The common case first. The special case is handled soon. |
| + |
| + if (need_wiggles) { |
| + // wiggle_plus = wiggle_minus = 10^estimated_power |
| + wiggle_plus->AssignBignum(*power_ten); |
| + wiggle_minus->AssignBignum(*power_ten); |
| + } |
| + // denominator = 2 * 2^-exponent with exponent < 0. |
| + denominator->AssignUInt16(1); |
| + denominator->ShiftLeft(1 - exponent); |
| + // numerator = significand * 2 * 10^-estimated_power |
| + // since v = significand * 2^exponent this is equivalent to |
| + // numerator = v * 10^-estimated_power * 2 * 2^-exponent. |
| + // Remember: numerator has been abused as power_ten. So no need to assign it |
| + // to itself. |
| + numerator->MultiplyByUInt64(significand); |
| + numerator->ShiftLeft(1); |
| + |
| + if (need_wiggles) { |
| + // The special case where the lower boundary is twice as close. |
| + // This time we have to look out for the exception too. |
| + uint64_t v_bits = Double(v).AsUint64(); |
| + if ((v_bits & Double::kSignificandMask) == 0 && |
| + // The only exception where a significand == 0 has its boundaries at |
| + // "normal" distances: |
| + (v_bits & Double::kExponentMask) != kMinimalNormalizedExponent) { |
| + numerator->ShiftLeft(1); // *2 |
| + denominator->ShiftLeft(1); // *2 |
| + wiggle_plus->ShiftLeft(1); // *2 |
| + } |
| + } |
| +} |
| + |
| + |
| +// v = significand * 2^exponent |
| +// The initial start values consist of: |
| +// - a scaled numerator: s.t. numerator/denominator == v / 10^estimated_power. |
| +// - a scaled (common) denominator. |
| +// - the scaled range a double has towards -infinity while still being |
| +// considered to be equal to v. In other words: the difference between v and |
| +// its lower boundary. |
| +// - the same room towards +infinity. |
| +// The scaling consist of multiplying the numerator by 10^estimated_power, or |
| +// (if the estimated_power is negative) by multiplying the denominator |
| +// by 10^-estimated_power. |
| +// Note that the wiggle-room is scaled too. If the common denominator has been |
| +// scaled, then the wiggles are automatically scaled. Otherwise they are |
| +// multiplied by the scaling factor, too. |
| +// |
| +// Let ep == estimated_power, then the returned values will satisfy: |
| +// v / 10^ep = numerator / denominator. |
| +// v's boundarys m- and m+: |
| +// m- / 10^ep == v / 10^ep - wiggle_minus / denominator |
| +// m+ / 10^ep == v / 10^ep + wiggle_plus / denominator |
| +// Or in other words: |
| +// m- == v - wiggle_minus * 10^ep / denominator; |
| +// m+ == v + wiggle_plus * 10^ep / denominator; |
| +// |
| +// Since 10^(k-1) <= v < 10^k (with k == estimated_power) |
| +// or 10^k <= v < 10^(k+1) |
| +// we then have 0.1 <= numerator/denominator < 1 |
| +// or 1 <= numerator/denominator < 10 |
| +// |
| +// It is then easy to kickstart the digit-generation routine. |
| +static void InitialScaledStartValues(double v, int estimated_power, |
| + bool need_wiggles, |
| + Bignum* numerator, Bignum* denominator, |
| + Bignum* wiggle_minus, |
| + Bignum* wiggle_plus) { |
| + if (Double(v).Exponent() >= 0) { |
| + InitialScaledStartValuesPositiveExponent( |
| + v, estimated_power, need_wiggles, |
| + numerator, denominator, wiggle_minus, wiggle_plus); |
| + } else if (estimated_power >= 0) { |
| + InitialScaledStartValuesNegativeExponentPositivePower( |
| + v, estimated_power, need_wiggles, |
| + numerator, denominator, wiggle_minus, wiggle_plus); |
| + } else { |
| + InitialScaledStartValuesNegativeExponentNegativePower( |
| + v, estimated_power, need_wiggles, |
| + numerator, denominator, wiggle_minus, wiggle_plus); |
| + } |
| +} |
| + |
| + |
| +// This routine multiplies numerator/denominator so that its values lies in the |
| +// range 1-10. That is after a call to this function we have: |
| +// 1 <= (numerator + wiggle_plus) /denominator < 10. |
| +// In some cases estimated_power was too low, and this is already the case. We |
| +// then simply adjust estimated_power so that 10^(k-1) <= v < 10^k (with k == |
| +// estimated_power) but do not touch the numerator or denominator. |
| +// Otherwise the routine multiplies the numerator and the wiggles by 10. |
| +static void FixupMultiply10(int estimated_power, bool is_even, |
| + int* power, |
| + Bignum* numerator, Bignum* denominator, |
| + Bignum* wiggle_minus, Bignum* wiggle_plus) { |
| + bool in_range; |
| + if (is_even) { |
| + // For IEEE doubles half-way cases (in decimal system numbers ending with 5) |
| + // are rounded to the closest floating-point number with even significand. |
| + in_range = Bignum::PlusCompare(*numerator, *wiggle_plus, *denominator) >= 0; |
| + } else { |
| + in_range = Bignum::PlusCompare(*numerator, *wiggle_plus, *denominator) > 0; |
| + } |
| + if (in_range) { |
| + // Since numerator + wiggle_plus >= denominator we already have |
| + // 1 <= numerator/denominator < 10. Simply update the estimated_power. |
| + *power = estimated_power + 1; |
| + } else { |
| + *power = estimated_power; |
| + numerator->Times10(); |
| + if (Bignum::Equal(*wiggle_minus, *wiggle_plus)) { |
| + wiggle_minus->Times10(); |
| + wiggle_plus->AssignBignum(*wiggle_minus); |
| + } else { |
| + wiggle_minus->Times10(); |
| + wiggle_plus->Times10(); |
| + } |
| + } |
| +} |
| + |
| + |
| +// Precondition: 0 <= (numerator+wiggle_plus) / denominator < 10. |
| +// If 1 <= (numerator+wiggle_plus) / denominator < 10 then no leading 0 digit |
| +// will be produced. This should be the standard precondition. |
| +// Produces the least amount of digits so that the result lies in the wiggle |
|
William Hesse
2010/11/15 15:48:30
Give more big picture comments - result lying in t
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| +// room. Let V the value written in the buffer, and |
| +// m- := (numerator - wiggle_minus) / denominator |
| +// m+ := (numerator + wiggle_plus) / denominator |
| +// <? := '<=' if is_even and '<' otherwise, then |
| +// m- <? V <? m+ |
| +// In other words the written buffer would read as the input number. |
| +static void GenerateDigits(Bignum* numerator, Bignum* denominator, |
|
William Hesse
2010/11/15 15:48:30
GenerateShortestDigits?
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + Bignum* wiggle_minus, Bignum* wiggle_plus, |
| + bool is_even, |
| + Vector<char> buffer, int* length) { |
| + // Small optimization: if wiggle_minus and wiggle_plus are the same just reuse |
| + // one of the two bignums. |
| + if (Bignum::Equal(*wiggle_minus, *wiggle_plus)) { |
| + wiggle_plus = wiggle_minus; |
| + } |
| + *length = 0; |
| + while (true) { |
| + uint16_t digit; |
| + digit = numerator->DivideModuloIntBignum(*denominator); |
| + // digit = numerator / denominator (integer division). |
| + // numerator = numerator % denominator. |
| + buffer[(*length)++] = digit + '0'; |
| + |
| + // Can we stop already? |
| + bool in_wiggle_room_minus; |
| + bool in_wiggle_room_plus; |
| + if (is_even) { |
| + in_wiggle_room_minus = Bignum::LessEqual(*numerator, *wiggle_minus); |
| + } else { |
| + in_wiggle_room_minus = Bignum::Less(*numerator, *wiggle_minus); |
| + } |
| + if (is_even) { |
| + in_wiggle_room_plus = |
| + Bignum::PlusCompare(*numerator, *wiggle_plus, *denominator) >= 0; |
| + } else { |
| + in_wiggle_room_plus = |
| + Bignum::PlusCompare(*numerator, *wiggle_plus, *denominator) > 0; |
| + } |
| + if (!in_wiggle_room_minus && !in_wiggle_room_plus) { |
| + // Prepare for next iteration. |
| + numerator->Times10(); |
| + wiggle_minus->Times10(); |
| + // We optimized wiggle_plus to be equal to wiggle_minus (if they share the |
| + // same value). So don't multiply wiggle_plus if they point to the same |
| + // object. |
| + if (wiggle_minus != wiggle_plus) { |
| + wiggle_plus->Times10(); |
| + } |
| + } else if (in_wiggle_room_minus && in_wiggle_room_plus) { |
| + // Let's see if 2*numerator < denominator. |
| + // If yes, then the next digit would be < 5 and we can round down. |
| + int compare = Bignum::PlusCompare(*numerator, *numerator, *denominator); |
| + if (compare < 0) { |
| + // Remaining digits are less than .5. -> Round down (== do nothing). |
| + } else if (compare > 0) { |
| + // Remaining digits are more than .5 of denominator. -> Round up. |
| + // Note that the last digit could not be a '9' as otherwise the whole |
| + // loop would have stopped earlier. |
| + // We still have an assert here in case the preconditions were not |
| + // satisfied. |
| + ASSERT(buffer[(*length) - 1] != '9'); |
| + buffer[(*length) - 1]++; |
| + } else { |
| + // Halfway case. |
| + // TODO(floitsch): need a way to solve half-way cases. |
| + // For now let's round towards even (since this is what Gay seems to |
| + // do). |
| + |
| + if ((buffer[(*length) - 1] - '0') % 2 == 0) { |
| + // Round down => Do nothing. |
| + } else { |
| + ASSERT(buffer[(*length) - 1] != '9'); |
| + buffer[(*length) - 1]++; |
| + } |
| + } |
| + return; |
| + } else if (in_wiggle_room_minus) { |
| + // Round down (== do nothing). |
| + return; |
| + } else { // in_wiggle_room_plus |
| + // Round up. |
| + // Note again that the last digit could not be '9' since this would have |
| + // stopped the loop earlier. |
| + // We still have an ASSERT here, in case the preconditions were not |
| + // satisfied. |
| + ASSERT(buffer[(*length) -1] != '9'); |
| + buffer[(*length) - 1]++; |
| + return; |
| + } |
| + } |
| +} |
| + |
| + |
| +static int NormalizedExponent(uint64_t significand, int exponent) { |
| + ASSERT(significand != 0); |
| + while ((significand & Double::kHiddenBit) == 0) { |
| + significand = significand << 1; |
| + exponent = exponent - 1; |
| + } |
| + return exponent; |
| +} |
| + |
| + |
| +static void GenerateCountedDigits(int count, int* decimal_point, |
| + Bignum* numerator, Bignum* denominator, |
| + Vector<char>(buffer), int* length) { |
| + ASSERT(count >= 0); |
| + for (int i = 0; i < count - 1; ++i) { |
| + uint16_t digit; |
| + digit = numerator->DivideModuloIntBignum(*denominator); |
| + // digit = numerator / denominator (integer division). |
|
William Hesse
2010/11/15 15:48:30
Include "Assumes numerator / denominator < 10" (or
Florian Loitsch
2010/11/16 14:32:06
added ASSERT.
|
| + // numerator = numerator % denominator. |
| + buffer[i] = digit + '0'; |
| + // Prepare for next iteration. |
| + numerator->Times10(); |
| + } |
| + // Generate the last digit. |
| + uint16_t digit; |
| + digit = numerator->DivideModuloIntBignum(*denominator); |
| + if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { |
| + digit++; |
| + } |
| + buffer[count - 1] = digit + '0'; |
| + // Correct bad digits (in case we had a sequence of '9's). |
|
William Hesse
2010/11/15 15:48:30
Propagate the carry until we hit a non-'9' or til
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + for (int i = count - 1; i > 0; --i) { |
| + if (buffer[i] != '0' + 10) break; |
| + buffer[i] = '0'; |
| + buffer[i - 1]++; |
| + } |
| + if (buffer[0] == '0' + 10) { |
|
William Hesse
2010/11/15 15:48:30
Propagate a carry past the top place.
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + buffer[0] = '1'; |
| + (*decimal_point)++; |
| + } |
| + *length = count; |
| +} |
| + |
| + |
| +static void BignumToFixed(int requested_digits, int* decimal_point, |
| + Bignum* numerator, Bignum* denominator, |
| + Vector<char>(buffer), int* length) { |
| + // The requested digits correspond to the digits after the point. |
| + // The variable 'needed_digits' includes the digits before the point. |
| + int needed_digits; |
| + // Note that we have to look at more than just the requested_digits, since |
| + // a number could be rounded up. Example: v=0.5 with requested_digits=0. |
| + // Even though the power of v equals 0 we can't just stop here. |
| + if (-(*decimal_point) > requested_digits) { |
|
William Hesse
2010/11/15 15:48:30
Explain this. People don't know what all these qu
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + *decimal_point = -requested_digits; |
| + *length = 0; |
| + return; |
| + } else if (-(*decimal_point) == requested_digits) { |
| + *decimal_point = -requested_digits; |
| + denominator->Times10(); // Bring fraction back to range 0.1 - 1. |
|
William Hesse
2010/11/15 15:48:30
Why does this bring the fraction to that range?
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + if (Bignum::PlusCompare(*numerator, *numerator, *denominator) >= 0) { |
| + // If the fraction is >= 0.5 then we have to include the rounded |
| + // digit. |
| + buffer[0] = '1'; |
| + *length = 1; |
| + (*decimal_point)++; |
| + } else { |
| + // Note that we caught most of similar cases earlier. |
| + *length = 0; |
| + } |
| + return; |
| + } else { |
| + needed_digits = (*decimal_point) + requested_digits; |
| + } |
| + GenerateCountedDigits(needed_digits, decimal_point, |
| + numerator, denominator, |
| + buffer, length); |
| +} |
| + |
| + |
| +void BignumDtoa(double v, BignumDtoaMode mode, int requested_digits, |
| + Vector<char> buffer, int* length, int* decimal_point) { |
| + ASSERT(v > 0); |
| + ASSERT(!Double(v).IsSpecial()); |
| + uint64_t significand = Double(v).Significand(); |
| + bool is_even = (significand & 1) == 0; |
| + int exponent = Double(v).Exponent(); |
| + int normalized_exponent = NormalizedExponent(significand, exponent); |
| + // estimated_power might be too low by 1. |
| + int estimated_power = EstimatePower(normalized_exponent); |
| + bool need_wiggles = (mode == BIGNUM_DTOA_SHORTEST); |
|
William Hesse
2010/11/15 15:48:30
bool compute_shortest_approximation =, instead of
Florian Loitsch
2010/11/16 14:32:06
renamed to need_boundary_deltas.
|
| + |
| + // Shortcut for Fixed. |
| + // The requested digits correspond to the digits after the point. If the |
| + // number is much too small, then there is no need in trying to get any |
| + // digits. |
| + if (mode == BIGNUM_DTOA_FIXED && -estimated_power - 1 > requested_digits) { |
| + buffer[0] = '\0'; |
| + *length = 0; |
| + // Set decimal-point to -requested_digits. This is what Gay does. |
| + // Note that it should not have any effect anyways since the string is |
| + // empty. |
| + *decimal_point = -requested_digits; |
| + return; |
| + } |
| + |
| + Bignum numerator; |
| + Bignum denominator; |
| + Bignum wiggle_minus; |
| + Bignum wiggle_plus; |
| + // Make sure the bignum can grow large enough. The smallest double equals |
| + // 4e-324. In this case the denominator needs less than 324*4 binary digits. |
|
William Hesse
2010/11/15 15:48:30
fewer than
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + // The maximum double is 1.7976931348623157e308 which needs less than |
|
William Hesse
2010/11/15 15:48:30
fewer
Florian Loitsch
2010/11/16 14:32:06
Done.
|
| + // 308*4 binary digits. |
| + ASSERT(Bignum::kMaxSignificantBits >= 324*4); |
| + InitialScaledStartValues(v, estimated_power, need_wiggles, |
| + &numerator, &denominator, |
| + &wiggle_minus, &wiggle_plus); |
| + FixupMultiply10(estimated_power, is_even, decimal_point, |
| + &numerator, &denominator, |
| + &wiggle_minus, &wiggle_plus); |
| + switch (mode) { |
| + case BIGNUM_DTOA_SHORTEST: |
| + GenerateDigits(&numerator, &denominator, |
| + &wiggle_minus, &wiggle_plus, |
| + is_even, buffer, length); |
| + break; |
| + case BIGNUM_DTOA_FIXED: |
| + BignumToFixed(requested_digits, decimal_point, |
| + &numerator, &denominator, |
| + buffer, length); |
| + break; |
| + case BIGNUM_DTOA_PRECISION: |
| + GenerateCountedDigits(requested_digits, decimal_point, |
| + &numerator, &denominator, |
| + buffer, length); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + buffer[*length] = '\0'; |
| +} |
| + |
| +} } // namespace v8::internal |