/* * Copyright (C) 2012 Google Inc. 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 "Decimal.h" #include "moz-decimal-utils.h" #include #include namespace WebCore { namespace DecimalPrivate { static int const ExponentMax = 1023; static int const ExponentMin = -1023; static int const Precision = 18; static const uint64_t MaxCoefficient = UINT64_C(0x16345785D89FFFF); // 999999999999999999 == 18 9's // This class handles Decimal special values. class SpecialValueHandler { WTF_MAKE_NONCOPYABLE(SpecialValueHandler); public: enum HandleResult { BothFinite, BothInfinity, EitherNaN, LHSIsInfinity, RHSIsInfinity, }; SpecialValueHandler(const Decimal& lhs, const Decimal& rhs); HandleResult handle(); Decimal value() const; private: enum Result { ResultIsLHS, ResultIsRHS, ResultIsUnknown, }; const Decimal& m_lhs; const Decimal& m_rhs; Result m_result; }; SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs) : m_lhs(lhs), m_rhs(rhs), m_result(ResultIsUnknown) { } SpecialValueHandler::HandleResult SpecialValueHandler::handle() { if (m_lhs.isFinite() && m_rhs.isFinite()) return BothFinite; const Decimal::EncodedData::FormatClass lhsClass = m_lhs.value().formatClass(); const Decimal::EncodedData::FormatClass rhsClass = m_rhs.value().formatClass(); if (lhsClass == Decimal::EncodedData::ClassNaN) { m_result = ResultIsLHS; return EitherNaN; } if (rhsClass == Decimal::EncodedData::ClassNaN) { m_result = ResultIsRHS; return EitherNaN; } if (lhsClass == Decimal::EncodedData::ClassInfinity) return rhsClass == Decimal::EncodedData::ClassInfinity ? BothInfinity : LHSIsInfinity; if (rhsClass == Decimal::EncodedData::ClassInfinity) return RHSIsInfinity; ASSERT_NOT_REACHED(); return BothFinite; } Decimal SpecialValueHandler::value() const { switch (m_result) { case ResultIsLHS: return m_lhs; case ResultIsRHS: return m_rhs; case ResultIsUnknown: default: ASSERT_NOT_REACHED(); return m_lhs; } } // This class is used for 128 bit unsigned integer arithmetic. class UInt128 { public: UInt128(uint64_t low, uint64_t high) : m_high(high), m_low(low) { } UInt128& operator/=(uint32_t); uint64_t high() const { return m_high; } uint64_t low() const { return m_low; } static UInt128 multiply(uint64_t u, uint64_t v) { return UInt128(u * v, multiplyHigh(u, v)); } private: static uint32_t highUInt32(uint64_t x) { return static_cast(x >> 32); } static uint32_t lowUInt32(uint64_t x) { return static_cast(x & ((static_cast(1) << 32) - 1)); } bool isZero() const { return !m_low && !m_high; } static uint64_t makeUInt64(uint32_t low, uint32_t high) { return low | (static_cast(high) << 32); } static uint64_t multiplyHigh(uint64_t, uint64_t); uint64_t m_high; uint64_t m_low; }; UInt128& UInt128::operator/=(const uint32_t divisor) { ASSERT(divisor); if (!m_high) { m_low /= divisor; return *this; } uint32_t dividend[4]; dividend[0] = lowUInt32(m_low); dividend[1] = highUInt32(m_low); dividend[2] = lowUInt32(m_high); dividend[3] = highUInt32(m_high); uint32_t quotient[4]; uint32_t remainder = 0; for (int i = 3; i >= 0; --i) { const uint64_t work = makeUInt64(dividend[i], remainder); remainder = static_cast(work % divisor); quotient[i] = static_cast(work / divisor); } m_low = makeUInt64(quotient[0], quotient[1]); m_high = makeUInt64(quotient[2], quotient[3]); return *this; } // Returns high 64bit of 128bit product. uint64_t UInt128::multiplyHigh(uint64_t u, uint64_t v) { const uint64_t uLow = lowUInt32(u); const uint64_t uHigh = highUInt32(u); const uint64_t vLow = lowUInt32(v); const uint64_t vHigh = highUInt32(v); const uint64_t partialProduct = uHigh * vLow + highUInt32(uLow * vLow); return uHigh * vHigh + highUInt32(partialProduct) + highUInt32(uLow * vHigh + lowUInt32(partialProduct)); } static int countDigits(uint64_t x) { int numberOfDigits = 0; for (uint64_t powerOfTen = 1; x >= powerOfTen; powerOfTen *= 10) { ++numberOfDigits; if (powerOfTen >= std::numeric_limits::max() / 10) break; } return numberOfDigits; } static uint64_t scaleDown(uint64_t x, int n) { ASSERT(n >= 0); while (n > 0 && x) { x /= 10; --n; } return x; } static uint64_t scaleUp(uint64_t x, int n) { ASSERT(n >= 0); ASSERT(n < Precision); uint64_t y = 1; uint64_t z = 10; for (;;) { if (n & 1) y = y * z; n >>= 1; if (!n) return x * y; z = z * z; } } } // namespace DecimalPrivate using namespace DecimalPrivate; Decimal::EncodedData::EncodedData(Sign sign, FormatClass formatClass) : m_coefficient(0) , m_exponent(0) , m_formatClass(formatClass) , m_sign(sign) { } Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient) : m_formatClass(coefficient ? ClassNormal : ClassZero) , m_sign(sign) { if (exponent >= ExponentMin && exponent <= ExponentMax) { while (coefficient > MaxCoefficient) { coefficient /= 10; ++exponent; } } if (exponent > ExponentMax) { m_coefficient = 0; m_exponent = 0; m_formatClass = ClassInfinity; return; } if (exponent < ExponentMin) { m_coefficient = 0; m_exponent = 0; m_formatClass = ClassZero; return; } m_coefficient = coefficient; m_exponent = static_cast(exponent); } bool Decimal::EncodedData::operator==(const EncodedData& another) const { return m_sign == another.m_sign && m_formatClass == another.m_formatClass && m_exponent == another.m_exponent && m_coefficient == another.m_coefficient; } Decimal::Decimal(int32_t i32) : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast(-static_cast(i32)) : static_cast(i32)) { } Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient) : m_data(sign, coefficient ? exponent : 0, coefficient) { } Decimal::Decimal(const EncodedData& data) : m_data(data) { } Decimal::Decimal(const Decimal& other) : m_data(other.m_data) { } Decimal& Decimal::operator=(const Decimal& other) { m_data = other.m_data; return *this; } Decimal& Decimal::operator+=(const Decimal& other) { m_data = (*this + other).m_data; return *this; } Decimal& Decimal::operator-=(const Decimal& other) { m_data = (*this - other).m_data; return *this; } Decimal& Decimal::operator*=(const Decimal& other) { m_data = (*this * other).m_data; return *this; } Decimal& Decimal::operator/=(const Decimal& other) { m_data = (*this / other).m_data; return *this; } Decimal Decimal::operator-() const { if (isNaN()) return *this; Decimal result(*this); result.m_data.setSign(invertSign(m_data.sign())); return result; } Decimal Decimal::operator+(const Decimal& rhs) const { const Decimal& lhs = *this; const Sign lhsSign = lhs.sign(); const Sign rhsSign = rhs.sign(); SpecialValueHandler handler(lhs, rhs); switch (handler.handle()) { case SpecialValueHandler::BothFinite: break; case SpecialValueHandler::BothInfinity: return lhsSign == rhsSign ? lhs : nan(); case SpecialValueHandler::EitherNaN: return handler.value(); case SpecialValueHandler::LHSIsInfinity: return lhs; case SpecialValueHandler::RHSIsInfinity: return rhs; } const AlignedOperands alignedOperands = alignOperands(lhs, rhs); const uint64_t result = lhsSign == rhsSign ? alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient : alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient; if (lhsSign == Negative && rhsSign == Positive && !result) return Decimal(Positive, alignedOperands.exponent, 0); return static_cast(result) >= 0 ? Decimal(lhsSign, alignedOperands.exponent, result) : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast(result)); } Decimal Decimal::operator-(const Decimal& rhs) const { const Decimal& lhs = *this; const Sign lhsSign = lhs.sign(); const Sign rhsSign = rhs.sign(); SpecialValueHandler handler(lhs, rhs); switch (handler.handle()) { case SpecialValueHandler::BothFinite: break; case SpecialValueHandler::BothInfinity: return lhsSign == rhsSign ? nan() : lhs; case SpecialValueHandler::EitherNaN: return handler.value(); case SpecialValueHandler::LHSIsInfinity: return lhs; case SpecialValueHandler::RHSIsInfinity: return infinity(invertSign(rhsSign)); } const AlignedOperands alignedOperands = alignOperands(lhs, rhs); const uint64_t result = lhsSign == rhsSign ? alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient : alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient; if (lhsSign == Negative && rhsSign == Negative && !result) return Decimal(Positive, alignedOperands.exponent, 0); return static_cast(result) >= 0 ? Decimal(lhsSign, alignedOperands.exponent, result) : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast(result)); } Decimal Decimal::operator*(const Decimal& rhs) const { const Decimal& lhs = *this; const Sign lhsSign = lhs.sign(); const Sign rhsSign = rhs.sign(); const Sign resultSign = lhsSign == rhsSign ? Positive : Negative; SpecialValueHandler handler(lhs, rhs); switch (handler.handle()) { case SpecialValueHandler::BothFinite: { const uint64_t lhsCoefficient = lhs.m_data.coefficient(); const uint64_t rhsCoefficient = rhs.m_data.coefficient(); int resultExponent = lhs.exponent() + rhs.exponent(); UInt128 work(UInt128::multiply(lhsCoefficient, rhsCoefficient)); while (work.high()) { work /= 10; ++resultExponent; } return Decimal(resultSign, resultExponent, work.low()); } case SpecialValueHandler::BothInfinity: return infinity(resultSign); case SpecialValueHandler::EitherNaN: return handler.value(); case SpecialValueHandler::LHSIsInfinity: return rhs.isZero() ? nan() : infinity(resultSign); case SpecialValueHandler::RHSIsInfinity: return lhs.isZero() ? nan() : infinity(resultSign); } ASSERT_NOT_REACHED(); return nan(); } Decimal Decimal::operator/(const Decimal& rhs) const { const Decimal& lhs = *this; const Sign lhsSign = lhs.sign(); const Sign rhsSign = rhs.sign(); const Sign resultSign = lhsSign == rhsSign ? Positive : Negative; SpecialValueHandler handler(lhs, rhs); switch (handler.handle()) { case SpecialValueHandler::BothFinite: break; case SpecialValueHandler::BothInfinity: return nan(); case SpecialValueHandler::EitherNaN: return handler.value(); case SpecialValueHandler::LHSIsInfinity: return infinity(resultSign); case SpecialValueHandler::RHSIsInfinity: return zero(resultSign); } ASSERT(lhs.isFinite()); ASSERT(rhs.isFinite()); if (rhs.isZero()) return lhs.isZero() ? nan() : infinity(resultSign); int resultExponent = lhs.exponent() - rhs.exponent(); if (lhs.isZero()) return Decimal(resultSign, resultExponent, 0); uint64_t remainder = lhs.m_data.coefficient(); const uint64_t divisor = rhs.m_data.coefficient(); uint64_t result = 0; while (result < MaxCoefficient / 100) { while (remainder < divisor) { remainder *= 10; result *= 10; --resultExponent; } result += remainder / divisor; remainder %= divisor; if (!remainder) break; } if (remainder > divisor / 2) ++result; return Decimal(resultSign, resultExponent, result); } bool Decimal::operator==(const Decimal& rhs) const { if (isNaN() || rhs.isNaN()) return false; return m_data == rhs.m_data || compareTo(rhs).isZero(); } bool Decimal::operator!=(const Decimal& rhs) const { if (isNaN() || rhs.isNaN()) return true; if (m_data == rhs.m_data) return false; const Decimal result = compareTo(rhs); if (result.isNaN()) return false; return !result.isZero(); } bool Decimal::operator<(const Decimal& rhs) const { const Decimal result = compareTo(rhs); if (result.isNaN()) return false; return !result.isZero() && result.isNegative(); } bool Decimal::operator<=(const Decimal& rhs) const { if (isNaN() || rhs.isNaN()) return false; if (m_data == rhs.m_data) return true; const Decimal result = compareTo(rhs); if (result.isNaN()) return false; return result.isZero() || result.isNegative(); } bool Decimal::operator>(const Decimal& rhs) const { const Decimal result = compareTo(rhs); if (result.isNaN()) return false; return !result.isZero() && result.isPositive(); } bool Decimal::operator>=(const Decimal& rhs) const { if (isNaN() || rhs.isNaN()) return false; if (m_data == rhs.m_data) return true; const Decimal result = compareTo(rhs); if (result.isNaN()) return false; return result.isZero() || !result.isNegative(); } Decimal Decimal::abs() const { Decimal result(*this); result.m_data.setSign(Positive); return result; } Decimal::AlignedOperands Decimal::alignOperands(const Decimal& lhs, const Decimal& rhs) { ASSERT(lhs.isFinite()); ASSERT(rhs.isFinite()); const int lhsExponent = lhs.exponent(); const int rhsExponent = rhs.exponent(); int exponent = std::min(lhsExponent, rhsExponent); uint64_t lhsCoefficient = lhs.m_data.coefficient(); uint64_t rhsCoefficient = rhs.m_data.coefficient(); if (lhsExponent > rhsExponent) { const int numberOfLHSDigits = countDigits(lhsCoefficient); if (numberOfLHSDigits) { const int lhsShiftAmount = lhsExponent - rhsExponent; const int overflow = numberOfLHSDigits + lhsShiftAmount - Precision; if (overflow <= 0) lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount); else { lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount - overflow); rhsCoefficient = scaleDown(rhsCoefficient, overflow); exponent += overflow; } } } else if (lhsExponent < rhsExponent) { const int numberOfRHSDigits = countDigits(rhsCoefficient); if (numberOfRHSDigits) { const int rhsShiftAmount = rhsExponent - lhsExponent; const int overflow = numberOfRHSDigits + rhsShiftAmount - Precision; if (overflow <= 0) rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount); else { rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount - overflow); lhsCoefficient = scaleDown(lhsCoefficient, overflow); exponent += overflow; } } } AlignedOperands alignedOperands; alignedOperands.exponent = exponent; alignedOperands.lhsCoefficient = lhsCoefficient; alignedOperands.rhsCoefficient = rhsCoefficient; return alignedOperands; } // Round toward positive infinity. // Note: Mac ports defines ceil(x) as wtf_ceil(x), so we can't use name "ceil" here. Decimal Decimal::ceiling() const { if (isSpecial()) return *this; if (exponent() >= 0) return *this; uint64_t coefficient = m_data.coefficient(); const int numberOfDigits = countDigits(coefficient); const int numberOfDropDigits = -exponent(); if (numberOfDigits < numberOfDropDigits) return isPositive() ? Decimal(1) : zero(Positive); uint64_t result = scaleDown(coefficient, numberOfDropDigits); uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits); if (droppedDigits && isPositive()) result += 1; return Decimal(sign(), 0, result); } Decimal Decimal::compareTo(const Decimal& rhs) const { const Decimal result(*this - rhs); switch (result.m_data.formatClass()) { case EncodedData::ClassInfinity: return result.isNegative() ? Decimal(-1) : Decimal(1); case EncodedData::ClassNaN: case EncodedData::ClassNormal: return result; case EncodedData::ClassZero: return zero(Positive); default: ASSERT_NOT_REACHED(); return nan(); } } // Round toward negative infinity. Decimal Decimal::floor() const { if (isSpecial()) return *this; if (exponent() >= 0) return *this; uint64_t coefficient = m_data.coefficient(); const int numberOfDigits = countDigits(coefficient); const int numberOfDropDigits = -exponent(); if (numberOfDigits < numberOfDropDigits) return isPositive() ? zero(Positive) : Decimal(-1); uint64_t result = scaleDown(coefficient, numberOfDropDigits); uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits); if (droppedDigits && isNegative()) { result += 1; } return Decimal(sign(), 0, result); } Decimal Decimal::fromDouble(double doubleValue) { if (std::isfinite(doubleValue)) return fromString(mozToString(doubleValue)); if (std::isinf(doubleValue)) return infinity(doubleValue < 0 ? Negative : Positive); return nan(); } Decimal Decimal::fromString(const String& str) { int exponent = 0; Sign exponentSign = Positive; int numberOfDigits = 0; int numberOfDigitsAfterDot = 0; int numberOfExtraDigits = 0; Sign sign = Positive; enum { StateDigit, StateDot, StateDotDigit, StateE, StateEDigit, StateESign, StateSign, StateStart, StateZero, } state = StateStart; #define HandleCharAndBreak(expected, nextState) \ if (ch == expected) { \ state = nextState; \ break; \ } #define HandleTwoCharsAndBreak(expected1, expected2, nextState) \ if (ch == expected1 || ch == expected2) { \ state = nextState; \ break; \ } uint64_t accumulator = 0; for (unsigned index = 0; index < str.length(); ++index) { const int ch = str[index]; switch (state) { case StateDigit: if (ch >= '0' && ch <= '9') { if (numberOfDigits < Precision) { ++numberOfDigits; accumulator *= 10; accumulator += ch - '0'; } else ++numberOfExtraDigits; break; } HandleCharAndBreak('.', StateDot); HandleTwoCharsAndBreak('E', 'e', StateE); return nan(); case StateDot: if (ch >= '0' && ch <= '9') { if (numberOfDigits < Precision) { ++numberOfDigits; ++numberOfDigitsAfterDot; accumulator *= 10; accumulator += ch - '0'; } state = StateDotDigit; break; } case StateDotDigit: if (ch >= '0' && ch <= '9') { if (numberOfDigits < Precision) { ++numberOfDigits; ++numberOfDigitsAfterDot; accumulator *= 10; accumulator += ch - '0'; } break; } HandleTwoCharsAndBreak('E', 'e', StateE); return nan(); case StateE: if (ch == '+') { exponentSign = Positive; state = StateESign; break; } if (ch == '-') { exponentSign = Negative; state = StateESign; break; } if (ch >= '0' && ch <= '9') { exponent = ch - '0'; state = StateEDigit; break; } return nan(); case StateEDigit: if (ch >= '0' && ch <= '9') { exponent *= 10; exponent += ch - '0'; if (exponent > ExponentMax + Precision) { if (accumulator) return exponentSign == Negative ? zero(Positive) : infinity(sign); return zero(sign); } state = StateEDigit; break; } return nan(); case StateESign: if (ch >= '0' && ch <= '9') { exponent = ch - '0'; state = StateEDigit; break; } return nan(); case StateSign: if (ch >= '1' && ch <= '9') { accumulator = ch - '0'; numberOfDigits = 1; state = StateDigit; break; } HandleCharAndBreak('0', StateZero); return nan(); case StateStart: if (ch >= '1' && ch <= '9') { accumulator = ch - '0'; numberOfDigits = 1; state = StateDigit; break; } if (ch == '-') { sign = Negative; state = StateSign; break; } if (ch == '+') { sign = Positive; state = StateSign; break; } HandleCharAndBreak('0', StateZero); HandleCharAndBreak('.', StateDot); return nan(); case StateZero: if (ch == '0') break; if (ch >= '1' && ch <= '9') { accumulator = ch - '0'; numberOfDigits = 1; state = StateDigit; break; } HandleCharAndBreak('.', StateDot); HandleTwoCharsAndBreak('E', 'e', StateE); return nan(); default: ASSERT_NOT_REACHED(); return nan(); } } if (state == StateZero) return zero(sign); if (state == StateDigit || state == StateEDigit || state == StateDotDigit) { int resultExponent = exponent * (exponentSign == Negative ? -1 : 1) - numberOfDigitsAfterDot + numberOfExtraDigits; if (resultExponent < ExponentMin) return zero(Positive); const int overflow = resultExponent - ExponentMax + 1; if (overflow > 0) { if (overflow + numberOfDigits - numberOfDigitsAfterDot > Precision) return infinity(sign); accumulator = scaleUp(accumulator, overflow); resultExponent -= overflow; } return Decimal(sign, resultExponent, accumulator); } return nan(); } Decimal Decimal::infinity(const Sign sign) { return Decimal(EncodedData(sign, EncodedData::ClassInfinity)); } Decimal Decimal::nan() { return Decimal(EncodedData(Positive, EncodedData::ClassNaN)); } Decimal Decimal::remainder(const Decimal& rhs) const { const Decimal quotient = *this / rhs; return quotient.isSpecial() ? quotient : *this - (quotient.isNegative() ? quotient.ceiling() : quotient.floor()) * rhs; } Decimal Decimal::round() const { if (isSpecial()) return *this; if (exponent() >= 0) return *this; uint64_t result = m_data.coefficient(); const int numberOfDigits = countDigits(result); const int numberOfDropDigits = -exponent(); if (numberOfDigits < numberOfDropDigits) return zero(Positive); // We're implementing round-half-away-from-zero, so we only need the one // (the most significant) fractional digit: result = scaleDown(result, numberOfDropDigits - 1); if (result % 10 >= 5) result += 10; result /= 10; return Decimal(sign(), 0, result); } double Decimal::toDouble() const { if (isFinite()) { bool valid; const double doubleValue = mozToDouble(toString(), &valid); return valid ? doubleValue : std::numeric_limits::quiet_NaN(); } if (isInfinity()) return isNegative() ? -std::numeric_limits::infinity() : std::numeric_limits::infinity(); return std::numeric_limits::quiet_NaN(); } String Decimal::toString() const { switch (m_data.formatClass()) { case EncodedData::ClassInfinity: return sign() ? "-Infinity" : "Infinity"; case EncodedData::ClassNaN: return "NaN"; case EncodedData::ClassNormal: case EncodedData::ClassZero: break; default: ASSERT_NOT_REACHED(); return ""; } StringBuilder builder; if (sign()) builder.append('-'); int originalExponent = exponent(); uint64_t coefficient = m_data.coefficient(); if (originalExponent < 0) { const int maxDigits = DBL_DIG; uint64_t lastDigit = 0; while (countDigits(coefficient) > maxDigits) { lastDigit = coefficient % 10; coefficient /= 10; ++originalExponent; } if (lastDigit >= 5) ++coefficient; while (originalExponent < 0 && coefficient && !(coefficient % 10)) { coefficient /= 10; ++originalExponent; } } const String digits = mozToString(coefficient); int coefficientLength = static_cast(digits.length()); const int adjustedExponent = originalExponent + coefficientLength - 1; if (originalExponent <= 0 && adjustedExponent >= -6) { if (!originalExponent) { builder.append(digits); return builder.toString(); } if (adjustedExponent >= 0) { for (int i = 0; i < coefficientLength; ++i) { builder.append(digits[i]); if (i == adjustedExponent) builder.append('.'); } return builder.toString(); } builder.appendLiteral("0."); for (int i = adjustedExponent + 1; i < 0; ++i) builder.append('0'); builder.append(digits); } else { builder.append(digits[0]); while (coefficientLength >= 2 && digits[coefficientLength - 1] == '0') --coefficientLength; if (coefficientLength >= 2) { builder.append('.'); for (int i = 1; i < coefficientLength; ++i) builder.append(digits[i]); } if (adjustedExponent) { builder.append(adjustedExponent < 0 ? "e" : "e+"); builder.appendNumber(adjustedExponent); } } return builder.toString(); } bool Decimal::toString(char* strBuf, size_t bufLength) const { ASSERT(bufLength > 0); String str = toString(); size_t length = str.copy(strBuf, bufLength); if (length < bufLength) { strBuf[length] = '\0'; return true; } strBuf[bufLength - 1] = '\0'; return false; } Decimal Decimal::zero(Sign sign) { return Decimal(EncodedData(sign, EncodedData::ClassZero)); } } // namespace WebCore