michael@0: // Copyright 2010 the V8 project authors. All rights reserved. michael@0: // Redistribution and use in source and binary forms, with or without michael@0: // modification, are permitted provided that the following conditions are michael@0: // met: michael@0: // michael@0: // * Redistributions of source code must retain the above copyright michael@0: // notice, this list of conditions and the following disclaimer. michael@0: // * Redistributions in binary form must reproduce the above michael@0: // copyright notice, this list of conditions and the following michael@0: // disclaimer in the documentation and/or other materials provided michael@0: // with the distribution. michael@0: // * Neither the name of Google Inc. nor the names of its michael@0: // contributors may be used to endorse or promote products derived michael@0: // from this software without specific prior written permission. michael@0: // michael@0: // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS michael@0: // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT michael@0: // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR michael@0: // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT michael@0: // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, michael@0: // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT michael@0: // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, michael@0: // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY michael@0: // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT michael@0: // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE michael@0: // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. michael@0: michael@0: #include michael@0: #include michael@0: michael@0: #include "strtod.h" michael@0: #include "bignum.h" michael@0: #include "cached-powers.h" michael@0: #include "ieee.h" michael@0: michael@0: namespace double_conversion { michael@0: michael@0: // 2^53 = 9007199254740992. michael@0: // Any integer with at most 15 decimal digits will hence fit into a double michael@0: // (which has a 53bit significand) without loss of precision. michael@0: static const int kMaxExactDoubleIntegerDecimalDigits = 15; michael@0: // 2^64 = 18446744073709551616 > 10^19 michael@0: static const int kMaxUint64DecimalDigits = 19; michael@0: michael@0: // Max double: 1.7976931348623157 x 10^308 michael@0: // Min non-zero double: 4.9406564584124654 x 10^-324 michael@0: // Any x >= 10^309 is interpreted as +infinity. michael@0: // Any x <= 10^-324 is interpreted as 0. michael@0: // Note that 2.5e-324 (despite being smaller than the min double) will be read michael@0: // as non-zero (equal to the min non-zero double). michael@0: static const int kMaxDecimalPower = 309; michael@0: static const int kMinDecimalPower = -324; michael@0: michael@0: // 2^64 = 18446744073709551616 michael@0: static const uint64_t kMaxUint64 = UINT64_2PART_C(0xFFFFFFFF, FFFFFFFF); michael@0: michael@0: michael@0: static const double exact_powers_of_ten[] = { michael@0: 1.0, // 10^0 michael@0: 10.0, michael@0: 100.0, michael@0: 1000.0, michael@0: 10000.0, michael@0: 100000.0, michael@0: 1000000.0, michael@0: 10000000.0, michael@0: 100000000.0, michael@0: 1000000000.0, michael@0: 10000000000.0, // 10^10 michael@0: 100000000000.0, michael@0: 1000000000000.0, michael@0: 10000000000000.0, michael@0: 100000000000000.0, michael@0: 1000000000000000.0, michael@0: 10000000000000000.0, michael@0: 100000000000000000.0, michael@0: 1000000000000000000.0, michael@0: 10000000000000000000.0, michael@0: 100000000000000000000.0, // 10^20 michael@0: 1000000000000000000000.0, michael@0: // 10^22 = 0x21e19e0c9bab2400000 = 0x878678326eac9 * 2^22 michael@0: 10000000000000000000000.0 michael@0: }; michael@0: static const int kExactPowersOfTenSize = ARRAY_SIZE(exact_powers_of_ten); michael@0: michael@0: // Maximum number of significant digits in the decimal representation. michael@0: // In fact the value is 772 (see conversions.cc), but to give us some margin michael@0: // we round up to 780. michael@0: static const int kMaxSignificantDecimalDigits = 780; michael@0: michael@0: static Vector TrimLeadingZeros(Vector buffer) { michael@0: for (int i = 0; i < buffer.length(); i++) { michael@0: if (buffer[i] != '0') { michael@0: return buffer.SubVector(i, buffer.length()); michael@0: } michael@0: } michael@0: return Vector(buffer.start(), 0); michael@0: } michael@0: michael@0: michael@0: static Vector TrimTrailingZeros(Vector buffer) { michael@0: for (int i = buffer.length() - 1; i >= 0; --i) { michael@0: if (buffer[i] != '0') { michael@0: return buffer.SubVector(0, i + 1); michael@0: } michael@0: } michael@0: return Vector(buffer.start(), 0); michael@0: } michael@0: michael@0: michael@0: static void CutToMaxSignificantDigits(Vector buffer, michael@0: int exponent, michael@0: char* significant_buffer, michael@0: int* significant_exponent) { michael@0: for (int i = 0; i < kMaxSignificantDecimalDigits - 1; ++i) { michael@0: significant_buffer[i] = buffer[i]; michael@0: } michael@0: // The input buffer has been trimmed. Therefore the last digit must be michael@0: // different from '0'. michael@0: ASSERT(buffer[buffer.length() - 1] != '0'); michael@0: // Set the last digit to be non-zero. This is sufficient to guarantee michael@0: // correct rounding. michael@0: significant_buffer[kMaxSignificantDecimalDigits - 1] = '1'; michael@0: *significant_exponent = michael@0: exponent + (buffer.length() - kMaxSignificantDecimalDigits); michael@0: } michael@0: michael@0: michael@0: // Trims the buffer and cuts it to at most kMaxSignificantDecimalDigits. michael@0: // If possible the input-buffer is reused, but if the buffer needs to be michael@0: // modified (due to cutting), then the input needs to be copied into the michael@0: // buffer_copy_space. michael@0: static void TrimAndCut(Vector buffer, int exponent, michael@0: char* buffer_copy_space, int space_size, michael@0: Vector* trimmed, int* updated_exponent) { michael@0: Vector left_trimmed = TrimLeadingZeros(buffer); michael@0: Vector right_trimmed = TrimTrailingZeros(left_trimmed); michael@0: exponent += left_trimmed.length() - right_trimmed.length(); michael@0: if (right_trimmed.length() > kMaxSignificantDecimalDigits) { michael@0: ASSERT(space_size >= kMaxSignificantDecimalDigits); michael@0: CutToMaxSignificantDigits(right_trimmed, exponent, michael@0: buffer_copy_space, updated_exponent); michael@0: *trimmed = Vector(buffer_copy_space, michael@0: kMaxSignificantDecimalDigits); michael@0: } else { michael@0: *trimmed = right_trimmed; michael@0: *updated_exponent = exponent; michael@0: } michael@0: } michael@0: michael@0: michael@0: // Reads digits from the buffer and converts them to a uint64. michael@0: // Reads in as many digits as fit into a uint64. michael@0: // When the string starts with "1844674407370955161" no further digit is read. michael@0: // Since 2^64 = 18446744073709551616 it would still be possible read another michael@0: // digit if it was less or equal than 6, but this would complicate the code. michael@0: static uint64_t ReadUint64(Vector buffer, michael@0: int* number_of_read_digits) { michael@0: uint64_t result = 0; michael@0: int i = 0; michael@0: while (i < buffer.length() && result <= (kMaxUint64 / 10 - 1)) { michael@0: int digit = buffer[i++] - '0'; michael@0: ASSERT(0 <= digit && digit <= 9); michael@0: result = 10 * result + digit; michael@0: } michael@0: *number_of_read_digits = i; michael@0: return result; michael@0: } michael@0: michael@0: michael@0: // Reads a DiyFp from the buffer. michael@0: // The returned DiyFp is not necessarily normalized. michael@0: // If remaining_decimals is zero then the returned DiyFp is accurate. michael@0: // Otherwise it has been rounded and has error of at most 1/2 ulp. michael@0: static void ReadDiyFp(Vector buffer, michael@0: DiyFp* result, michael@0: int* remaining_decimals) { michael@0: int read_digits; michael@0: uint64_t significand = ReadUint64(buffer, &read_digits); michael@0: if (buffer.length() == read_digits) { michael@0: *result = DiyFp(significand, 0); michael@0: *remaining_decimals = 0; michael@0: } else { michael@0: // Round the significand. michael@0: if (buffer[read_digits] >= '5') { michael@0: significand++; michael@0: } michael@0: // Compute the binary exponent. michael@0: int exponent = 0; michael@0: *result = DiyFp(significand, exponent); michael@0: *remaining_decimals = buffer.length() - read_digits; michael@0: } michael@0: } michael@0: michael@0: michael@0: static bool DoubleStrtod(Vector trimmed, michael@0: int exponent, michael@0: double* result) { michael@0: #if !defined(DOUBLE_CONVERSION_CORRECT_DOUBLE_OPERATIONS) michael@0: // On x86 the floating-point stack can be 64 or 80 bits wide. If it is michael@0: // 80 bits wide (as is the case on Linux) then double-rounding occurs and the michael@0: // result is not accurate. michael@0: // We know that Windows32 uses 64 bits and is therefore accurate. michael@0: // Note that the ARM simulator is compiled for 32bits. It therefore exhibits michael@0: // the same problem. michael@0: return false; michael@0: #endif michael@0: if (trimmed.length() <= kMaxExactDoubleIntegerDecimalDigits) { michael@0: int read_digits; michael@0: // The trimmed input fits into a double. michael@0: // If the 10^exponent (resp. 10^-exponent) fits into a double too then we michael@0: // can compute the result-double simply by multiplying (resp. dividing) the michael@0: // two numbers. michael@0: // This is possible because IEEE guarantees that floating-point operations michael@0: // return the best possible approximation. michael@0: if (exponent < 0 && -exponent < kExactPowersOfTenSize) { michael@0: // 10^-exponent fits into a double. michael@0: *result = static_cast(ReadUint64(trimmed, &read_digits)); michael@0: ASSERT(read_digits == trimmed.length()); michael@0: *result /= exact_powers_of_ten[-exponent]; michael@0: return true; michael@0: } michael@0: if (0 <= exponent && exponent < kExactPowersOfTenSize) { michael@0: // 10^exponent fits into a double. michael@0: *result = static_cast(ReadUint64(trimmed, &read_digits)); michael@0: ASSERT(read_digits == trimmed.length()); michael@0: *result *= exact_powers_of_ten[exponent]; michael@0: return true; michael@0: } michael@0: int remaining_digits = michael@0: kMaxExactDoubleIntegerDecimalDigits - trimmed.length(); michael@0: if ((0 <= exponent) && michael@0: (exponent - remaining_digits < kExactPowersOfTenSize)) { michael@0: // The trimmed string was short and we can multiply it with michael@0: // 10^remaining_digits. As a result the remaining exponent now fits michael@0: // into a double too. michael@0: *result = static_cast(ReadUint64(trimmed, &read_digits)); michael@0: ASSERT(read_digits == trimmed.length()); michael@0: *result *= exact_powers_of_ten[remaining_digits]; michael@0: *result *= exact_powers_of_ten[exponent - remaining_digits]; michael@0: return true; michael@0: } michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: michael@0: // Returns 10^exponent as an exact DiyFp. michael@0: // The given exponent must be in the range [1; kDecimalExponentDistance[. michael@0: static DiyFp AdjustmentPowerOfTen(int exponent) { michael@0: ASSERT(0 < exponent); michael@0: ASSERT(exponent < PowersOfTenCache::kDecimalExponentDistance); michael@0: // Simply hardcode the remaining powers for the given decimal exponent michael@0: // distance. michael@0: ASSERT(PowersOfTenCache::kDecimalExponentDistance == 8); michael@0: switch (exponent) { michael@0: case 1: return DiyFp(UINT64_2PART_C(0xa0000000, 00000000), -60); michael@0: case 2: return DiyFp(UINT64_2PART_C(0xc8000000, 00000000), -57); michael@0: case 3: return DiyFp(UINT64_2PART_C(0xfa000000, 00000000), -54); michael@0: case 4: return DiyFp(UINT64_2PART_C(0x9c400000, 00000000), -50); michael@0: case 5: return DiyFp(UINT64_2PART_C(0xc3500000, 00000000), -47); michael@0: case 6: return DiyFp(UINT64_2PART_C(0xf4240000, 00000000), -44); michael@0: case 7: return DiyFp(UINT64_2PART_C(0x98968000, 00000000), -40); michael@0: default: michael@0: UNREACHABLE(); michael@0: return DiyFp(0, 0); michael@0: } michael@0: } michael@0: michael@0: michael@0: // If the function returns true then the result is the correct double. michael@0: // Otherwise it is either the correct double or the double that is just below michael@0: // the correct double. michael@0: static bool DiyFpStrtod(Vector buffer, michael@0: int exponent, michael@0: double* result) { michael@0: DiyFp input; michael@0: int remaining_decimals; michael@0: ReadDiyFp(buffer, &input, &remaining_decimals); michael@0: // Since we may have dropped some digits the input is not accurate. michael@0: // If remaining_decimals is different than 0 than the error is at most michael@0: // .5 ulp (unit in the last place). michael@0: // We don't want to deal with fractions and therefore keep a common michael@0: // denominator. michael@0: const int kDenominatorLog = 3; michael@0: const int kDenominator = 1 << kDenominatorLog; michael@0: // Move the remaining decimals into the exponent. michael@0: exponent += remaining_decimals; michael@0: int error = (remaining_decimals == 0 ? 0 : kDenominator / 2); michael@0: michael@0: int old_e = input.e(); michael@0: input.Normalize(); michael@0: error <<= old_e - input.e(); michael@0: michael@0: ASSERT(exponent <= PowersOfTenCache::kMaxDecimalExponent); michael@0: if (exponent < PowersOfTenCache::kMinDecimalExponent) { michael@0: *result = 0.0; michael@0: return true; michael@0: } michael@0: DiyFp cached_power; michael@0: int cached_decimal_exponent; michael@0: PowersOfTenCache::GetCachedPowerForDecimalExponent(exponent, michael@0: &cached_power, michael@0: &cached_decimal_exponent); michael@0: michael@0: if (cached_decimal_exponent != exponent) { michael@0: int adjustment_exponent = exponent - cached_decimal_exponent; michael@0: DiyFp adjustment_power = AdjustmentPowerOfTen(adjustment_exponent); michael@0: input.Multiply(adjustment_power); michael@0: if (kMaxUint64DecimalDigits - buffer.length() >= adjustment_exponent) { michael@0: // The product of input with the adjustment power fits into a 64 bit michael@0: // integer. michael@0: ASSERT(DiyFp::kSignificandSize == 64); michael@0: } else { michael@0: // The adjustment power is exact. There is hence only an error of 0.5. michael@0: error += kDenominator / 2; michael@0: } michael@0: } michael@0: michael@0: input.Multiply(cached_power); michael@0: // The error introduced by a multiplication of a*b equals michael@0: // error_a + error_b + error_a*error_b/2^64 + 0.5 michael@0: // Substituting a with 'input' and b with 'cached_power' we have michael@0: // error_b = 0.5 (all cached powers have an error of less than 0.5 ulp), michael@0: // error_ab = 0 or 1 / kDenominator > error_a*error_b/ 2^64 michael@0: int error_b = kDenominator / 2; michael@0: int error_ab = (error == 0 ? 0 : 1); // We round up to 1. michael@0: int fixed_error = kDenominator / 2; michael@0: error += error_b + error_ab + fixed_error; michael@0: michael@0: old_e = input.e(); michael@0: input.Normalize(); michael@0: error <<= old_e - input.e(); michael@0: michael@0: // See if the double's significand changes if we add/subtract the error. michael@0: int order_of_magnitude = DiyFp::kSignificandSize + input.e(); michael@0: int effective_significand_size = michael@0: Double::SignificandSizeForOrderOfMagnitude(order_of_magnitude); michael@0: int precision_digits_count = michael@0: DiyFp::kSignificandSize - effective_significand_size; michael@0: if (precision_digits_count + kDenominatorLog >= DiyFp::kSignificandSize) { michael@0: // This can only happen for very small denormals. In this case the michael@0: // half-way multiplied by the denominator exceeds the range of an uint64. michael@0: // Simply shift everything to the right. michael@0: int shift_amount = (precision_digits_count + kDenominatorLog) - michael@0: DiyFp::kSignificandSize + 1; michael@0: input.set_f(input.f() >> shift_amount); michael@0: input.set_e(input.e() + shift_amount); michael@0: // We add 1 for the lost precision of error, and kDenominator for michael@0: // the lost precision of input.f(). michael@0: error = (error >> shift_amount) + 1 + kDenominator; michael@0: precision_digits_count -= shift_amount; michael@0: } michael@0: // We use uint64_ts now. This only works if the DiyFp uses uint64_ts too. michael@0: ASSERT(DiyFp::kSignificandSize == 64); michael@0: ASSERT(precision_digits_count < 64); michael@0: uint64_t one64 = 1; michael@0: uint64_t precision_bits_mask = (one64 << precision_digits_count) - 1; michael@0: uint64_t precision_bits = input.f() & precision_bits_mask; michael@0: uint64_t half_way = one64 << (precision_digits_count - 1); michael@0: precision_bits *= kDenominator; michael@0: half_way *= kDenominator; michael@0: DiyFp rounded_input(input.f() >> precision_digits_count, michael@0: input.e() + precision_digits_count); michael@0: if (precision_bits >= half_way + error) { michael@0: rounded_input.set_f(rounded_input.f() + 1); michael@0: } michael@0: // If the last_bits are too close to the half-way case than we are too michael@0: // inaccurate and round down. In this case we return false so that we can michael@0: // fall back to a more precise algorithm. michael@0: michael@0: *result = Double(rounded_input).value(); michael@0: if (half_way - error < precision_bits && precision_bits < half_way + error) { michael@0: // Too imprecise. The caller will have to fall back to a slower version. michael@0: // However the returned number is guaranteed to be either the correct michael@0: // double, or the next-lower double. michael@0: return false; michael@0: } else { michael@0: return true; michael@0: } michael@0: } michael@0: michael@0: michael@0: // Returns michael@0: // - -1 if buffer*10^exponent < diy_fp. michael@0: // - 0 if buffer*10^exponent == diy_fp. michael@0: // - +1 if buffer*10^exponent > diy_fp. michael@0: // Preconditions: michael@0: // buffer.length() + exponent <= kMaxDecimalPower + 1 michael@0: // buffer.length() + exponent > kMinDecimalPower michael@0: // buffer.length() <= kMaxDecimalSignificantDigits michael@0: static int CompareBufferWithDiyFp(Vector buffer, michael@0: int exponent, michael@0: DiyFp diy_fp) { michael@0: ASSERT(buffer.length() + exponent <= kMaxDecimalPower + 1); michael@0: ASSERT(buffer.length() + exponent > kMinDecimalPower); michael@0: ASSERT(buffer.length() <= kMaxSignificantDecimalDigits); michael@0: // Make sure that the Bignum will be able to hold all our numbers. michael@0: // Our Bignum implementation has a separate field for exponents. Shifts will michael@0: // consume at most one bigit (< 64 bits). michael@0: // ln(10) == 3.3219... michael@0: ASSERT(((kMaxDecimalPower + 1) * 333 / 100) < Bignum::kMaxSignificantBits); michael@0: Bignum buffer_bignum; michael@0: Bignum diy_fp_bignum; michael@0: buffer_bignum.AssignDecimalString(buffer); michael@0: diy_fp_bignum.AssignUInt64(diy_fp.f()); michael@0: if (exponent >= 0) { michael@0: buffer_bignum.MultiplyByPowerOfTen(exponent); michael@0: } else { michael@0: diy_fp_bignum.MultiplyByPowerOfTen(-exponent); michael@0: } michael@0: if (diy_fp.e() > 0) { michael@0: diy_fp_bignum.ShiftLeft(diy_fp.e()); michael@0: } else { michael@0: buffer_bignum.ShiftLeft(-diy_fp.e()); michael@0: } michael@0: return Bignum::Compare(buffer_bignum, diy_fp_bignum); michael@0: } michael@0: michael@0: michael@0: // Returns true if the guess is the correct double. michael@0: // Returns false, when guess is either correct or the next-lower double. michael@0: static bool ComputeGuess(Vector trimmed, int exponent, michael@0: double* guess) { michael@0: if (trimmed.length() == 0) { michael@0: *guess = 0.0; michael@0: return true; michael@0: } michael@0: if (exponent + trimmed.length() - 1 >= kMaxDecimalPower) { michael@0: *guess = Double::Infinity(); michael@0: return true; michael@0: } michael@0: if (exponent + trimmed.length() <= kMinDecimalPower) { michael@0: *guess = 0.0; michael@0: return true; michael@0: } michael@0: michael@0: if (DoubleStrtod(trimmed, exponent, guess) || michael@0: DiyFpStrtod(trimmed, exponent, guess)) { michael@0: return true; michael@0: } michael@0: if (*guess == Double::Infinity()) { michael@0: return true; michael@0: } michael@0: return false; michael@0: } michael@0: michael@0: double Strtod(Vector buffer, int exponent) { michael@0: char copy_buffer[kMaxSignificantDecimalDigits]; michael@0: Vector trimmed; michael@0: int updated_exponent; michael@0: TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, michael@0: &trimmed, &updated_exponent); michael@0: exponent = updated_exponent; michael@0: michael@0: double guess; michael@0: bool is_correct = ComputeGuess(trimmed, exponent, &guess); michael@0: if (is_correct) return guess; michael@0: michael@0: DiyFp upper_boundary = Double(guess).UpperBoundary(); michael@0: int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); michael@0: if (comparison < 0) { michael@0: return guess; michael@0: } else if (comparison > 0) { michael@0: return Double(guess).NextDouble(); michael@0: } else if ((Double(guess).Significand() & 1) == 0) { michael@0: // Round towards even. michael@0: return guess; michael@0: } else { michael@0: return Double(guess).NextDouble(); michael@0: } michael@0: } michael@0: michael@0: float Strtof(Vector buffer, int exponent) { michael@0: char copy_buffer[kMaxSignificantDecimalDigits]; michael@0: Vector trimmed; michael@0: int updated_exponent; michael@0: TrimAndCut(buffer, exponent, copy_buffer, kMaxSignificantDecimalDigits, michael@0: &trimmed, &updated_exponent); michael@0: exponent = updated_exponent; michael@0: michael@0: double double_guess; michael@0: bool is_correct = ComputeGuess(trimmed, exponent, &double_guess); michael@0: michael@0: float float_guess = static_cast(double_guess); michael@0: if (float_guess == double_guess) { michael@0: // This shortcut triggers for integer values. michael@0: return float_guess; michael@0: } michael@0: michael@0: // We must catch double-rounding. Say the double has been rounded up, and is michael@0: // now a boundary of a float, and rounds up again. This is why we have to michael@0: // look at previous too. michael@0: // Example (in decimal numbers): michael@0: // input: 12349 michael@0: // high-precision (4 digits): 1235 michael@0: // low-precision (3 digits): michael@0: // when read from input: 123 michael@0: // when rounded from high precision: 124. michael@0: // To do this we simply look at the neigbors of the correct result and see michael@0: // if they would round to the same float. If the guess is not correct we have michael@0: // to look at four values (since two different doubles could be the correct michael@0: // double). michael@0: michael@0: double double_next = Double(double_guess).NextDouble(); michael@0: double double_previous = Double(double_guess).PreviousDouble(); michael@0: michael@0: float f1 = static_cast(double_previous); michael@0: #if defined(DEBUG) michael@0: float f2 = float_guess; michael@0: #endif michael@0: float f3 = static_cast(double_next); michael@0: float f4; michael@0: if (is_correct) { michael@0: f4 = f3; michael@0: } else { michael@0: double double_next2 = Double(double_next).NextDouble(); michael@0: f4 = static_cast(double_next2); michael@0: } michael@0: ASSERT(f1 <= f2 && f2 <= f3 && f3 <= f4); michael@0: michael@0: // If the guess doesn't lie near a single-precision boundary we can simply michael@0: // return its float-value. michael@0: if (f1 == f4) { michael@0: return float_guess; michael@0: } michael@0: michael@0: ASSERT((f1 != f2 && f2 == f3 && f3 == f4) || michael@0: (f1 == f2 && f2 != f3 && f3 == f4) || michael@0: (f1 == f2 && f2 == f3 && f3 != f4)); michael@0: michael@0: // guess and next are the two possible canditates (in the same way that michael@0: // double_guess was the lower candidate for a double-precision guess). michael@0: float guess = f1; michael@0: float next = f4; michael@0: DiyFp upper_boundary; michael@0: if (guess == 0.0f) { michael@0: float min_float = 1e-45f; michael@0: upper_boundary = Double(static_cast(min_float) / 2).AsDiyFp(); michael@0: } else { michael@0: upper_boundary = Single(guess).UpperBoundary(); michael@0: } michael@0: int comparison = CompareBufferWithDiyFp(trimmed, exponent, upper_boundary); michael@0: if (comparison < 0) { michael@0: return guess; michael@0: } else if (comparison > 0) { michael@0: return next; michael@0: } else if ((Single(guess).Significand() & 1) == 0) { michael@0: // Round towards even. michael@0: return guess; michael@0: } else { michael@0: return next; michael@0: } michael@0: } michael@0: michael@0: } // namespace double_conversion