mfbt/decimal/Decimal.cpp

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 /*
     2  * Copyright (C) 2012 Google Inc. All rights reserved.
     3  *
     4  * Redistribution and use in source and binary forms, with or without
     5  * modification, are permitted provided that the following conditions are
     6  * met:
     7  *
     8  *     * Redistributions of source code must retain the above copyright
     9  * notice, this list of conditions and the following disclaimer.
    10  *     * Redistributions in binary form must reproduce the above
    11  * copyright notice, this list of conditions and the following disclaimer
    12  * in the documentation and/or other materials provided with the
    13  * distribution.
    14  *     * Neither the name of Google Inc. nor the names of its
    15  * contributors may be used to endorse or promote products derived from
    16  * this software without specific prior written permission.
    17  *
    18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    19  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    21  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    22  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    23  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    24  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    25  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    26  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    27  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    28  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    29  */
    31 #include "Decimal.h"
    32 #include "moz-decimal-utils.h"
    34 #include <algorithm>
    35 #include <float.h>
    37 using namespace moz_decimal_utils;
    39 namespace WebCore {
    41 namespace DecimalPrivate {
    43 static int const ExponentMax = 1023;
    44 static int const ExponentMin = -1023;
    45 static int const Precision = 18;
    47 static const uint64_t MaxCoefficient = UINT64_C(0x16345785D89FFFF); // 999999999999999999 == 18 9's
    49 // This class handles Decimal special values.
    50 class SpecialValueHandler {
    51     WTF_MAKE_NONCOPYABLE(SpecialValueHandler);
    52 public:
    53     enum HandleResult {
    54         BothFinite,
    55         BothInfinity,
    56         EitherNaN,
    57         LHSIsInfinity,
    58         RHSIsInfinity,
    59     };
    61     SpecialValueHandler(const Decimal& lhs, const Decimal& rhs);
    62     HandleResult handle();
    63     Decimal value() const;
    65 private:
    66     enum Result {
    67         ResultIsLHS,
    68         ResultIsRHS,
    69         ResultIsUnknown,
    70     };
    72     const Decimal& m_lhs;
    73     const Decimal& m_rhs;
    74     Result m_result;
    75 };
    77 SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs)
    78     : m_lhs(lhs), m_rhs(rhs), m_result(ResultIsUnknown)
    79 {
    80 }
    82 SpecialValueHandler::HandleResult SpecialValueHandler::handle()
    83 {
    84     if (m_lhs.isFinite() && m_rhs.isFinite())
    85         return BothFinite;
    87     const Decimal::EncodedData::FormatClass lhsClass = m_lhs.value().formatClass();
    88     const Decimal::EncodedData::FormatClass rhsClass = m_rhs.value().formatClass();
    89     if (lhsClass == Decimal::EncodedData::ClassNaN) {
    90         m_result = ResultIsLHS;
    91         return EitherNaN;
    92      }
    94     if (rhsClass == Decimal::EncodedData::ClassNaN) {
    95         m_result = ResultIsRHS;
    96         return EitherNaN;
    97      }
    99     if (lhsClass == Decimal::EncodedData::ClassInfinity)
   100         return rhsClass == Decimal::EncodedData::ClassInfinity ? BothInfinity : LHSIsInfinity;
   102     if (rhsClass == Decimal::EncodedData::ClassInfinity)
   103         return RHSIsInfinity;
   105     ASSERT_NOT_REACHED();
   106     return BothFinite;
   107 }
   109 Decimal SpecialValueHandler::value() const
   110 {
   111     switch (m_result) {
   112     case ResultIsLHS:
   113         return m_lhs;
   114     case ResultIsRHS:
   115         return m_rhs;
   116     case ResultIsUnknown:
   117     default:
   118         ASSERT_NOT_REACHED();
   119         return m_lhs;
   120     }
   121 }
   123 // This class is used for 128 bit unsigned integer arithmetic.
   124 class UInt128 {
   125 public:
   126     UInt128(uint64_t low, uint64_t high)
   127         : m_high(high), m_low(low)
   128     {
   129     }
   131     UInt128& operator/=(uint32_t);
   133     uint64_t high() const { return m_high; }
   134     uint64_t low() const { return m_low; }
   136     static UInt128 multiply(uint64_t u, uint64_t v) { return UInt128(u * v, multiplyHigh(u, v)); }
   138 private:
   139     static uint32_t highUInt32(uint64_t x) { return static_cast<uint32_t>(x >> 32); }
   140     static uint32_t lowUInt32(uint64_t x) { return static_cast<uint32_t>(x & ((static_cast<uint64_t>(1) << 32) - 1)); }
   141     bool isZero() const { return !m_low && !m_high; }
   142     static uint64_t makeUInt64(uint32_t low, uint32_t high) { return low | (static_cast<uint64_t>(high) << 32); }
   144     static uint64_t multiplyHigh(uint64_t, uint64_t);
   146     uint64_t m_high;
   147     uint64_t m_low;
   148 };
   150 UInt128& UInt128::operator/=(const uint32_t divisor)
   151 {
   152     ASSERT(divisor);
   154     if (!m_high) {
   155         m_low /= divisor;
   156         return *this;
   157     }
   159     uint32_t dividend[4];
   160     dividend[0] = lowUInt32(m_low);
   161     dividend[1] = highUInt32(m_low);
   162     dividend[2] = lowUInt32(m_high);
   163     dividend[3] = highUInt32(m_high);
   165     uint32_t quotient[4];
   166     uint32_t remainder = 0;
   167     for (int i = 3; i >= 0; --i) {
   168         const uint64_t work = makeUInt64(dividend[i], remainder);
   169         remainder = static_cast<uint32_t>(work % divisor);
   170         quotient[i] = static_cast<uint32_t>(work / divisor);
   171     }
   172     m_low = makeUInt64(quotient[0], quotient[1]);
   173     m_high = makeUInt64(quotient[2], quotient[3]);
   174     return *this;
   175 }
   177 // Returns high 64bit of 128bit product.
   178 uint64_t UInt128::multiplyHigh(uint64_t u, uint64_t v)
   179 {
   180     const uint64_t uLow = lowUInt32(u);
   181     const uint64_t uHigh = highUInt32(u);
   182     const uint64_t vLow = lowUInt32(v);
   183     const uint64_t vHigh = highUInt32(v);
   184     const uint64_t partialProduct = uHigh * vLow + highUInt32(uLow * vLow);
   185     return uHigh * vHigh + highUInt32(partialProduct) + highUInt32(uLow * vHigh + lowUInt32(partialProduct));
   186 }
   188 static int countDigits(uint64_t x)
   189 {
   190     int numberOfDigits = 0;
   191     for (uint64_t powerOfTen = 1; x >= powerOfTen; powerOfTen *= 10) {
   192         ++numberOfDigits;
   193         if (powerOfTen >= std::numeric_limits<uint64_t>::max() / 10)
   194             break;
   195     }
   196     return numberOfDigits;
   197 }
   199 static uint64_t scaleDown(uint64_t x, int n)
   200 {
   201     ASSERT(n >= 0);
   202     while (n > 0 && x) {
   203         x /= 10;
   204         --n;
   205     }
   206     return x;
   207 }
   209 static uint64_t scaleUp(uint64_t x, int n)
   210 {
   211     ASSERT(n >= 0);
   212     ASSERT(n < Precision);
   214     uint64_t y = 1;
   215     uint64_t z = 10;
   216     for (;;) {
   217         if (n & 1)
   218             y = y * z;
   220         n >>= 1;
   221         if (!n)
   222             return x * y;
   224         z = z * z;
   225     }
   226 }
   228 } // namespace DecimalPrivate
   230 using namespace DecimalPrivate;
   232 Decimal::EncodedData::EncodedData(Sign sign, FormatClass formatClass)
   233     : m_coefficient(0)
   234     , m_exponent(0)
   235     , m_formatClass(formatClass)
   236     , m_sign(sign)
   237 {
   238 }
   240 Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient)
   241     : m_formatClass(coefficient ? ClassNormal : ClassZero)
   242     , m_sign(sign)
   243 {
   244     if (exponent >= ExponentMin && exponent <= ExponentMax) {
   245         while (coefficient > MaxCoefficient) {
   246             coefficient /= 10;
   247             ++exponent;
   248         }
   249     }
   251     if (exponent > ExponentMax) {
   252         m_coefficient = 0;
   253         m_exponent = 0;
   254         m_formatClass = ClassInfinity;
   255         return;
   256     }
   258     if (exponent < ExponentMin) {
   259         m_coefficient = 0;
   260         m_exponent = 0;
   261         m_formatClass = ClassZero;
   262         return;
   263     }
   265     m_coefficient = coefficient;
   266     m_exponent = static_cast<int16_t>(exponent);
   267 }
   269 bool Decimal::EncodedData::operator==(const EncodedData& another) const
   270 {
   271     return m_sign == another.m_sign
   272         && m_formatClass == another.m_formatClass
   273         && m_exponent == another.m_exponent
   274         && m_coefficient == another.m_coefficient;
   275 }
   277 Decimal::Decimal(int32_t i32)
   278     : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(i32))
   279 {
   280 }
   282 Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
   283     : m_data(sign, coefficient ? exponent : 0, coefficient)
   284 {
   285 }
   287 Decimal::Decimal(const EncodedData& data)
   288     : m_data(data)
   289 {
   290 }
   292 Decimal::Decimal(const Decimal& other)
   293     : m_data(other.m_data)
   294 {
   295 }
   297 Decimal& Decimal::operator=(const Decimal& other)
   298 {
   299     m_data = other.m_data;
   300     return *this;
   301 }
   303 Decimal& Decimal::operator+=(const Decimal& other)
   304 {
   305     m_data = (*this + other).m_data;
   306     return *this;
   307 }
   309 Decimal& Decimal::operator-=(const Decimal& other)
   310 {
   311     m_data = (*this - other).m_data;
   312     return *this;
   313 }
   315 Decimal& Decimal::operator*=(const Decimal& other)
   316 {
   317     m_data = (*this * other).m_data;
   318     return *this;
   319 }
   321 Decimal& Decimal::operator/=(const Decimal& other)
   322 {
   323     m_data = (*this / other).m_data;
   324     return *this;
   325 }
   327 Decimal Decimal::operator-() const
   328 {
   329     if (isNaN())
   330         return *this;
   332     Decimal result(*this);
   333     result.m_data.setSign(invertSign(m_data.sign()));
   334     return result;
   335 }
   337 Decimal Decimal::operator+(const Decimal& rhs) const
   338 {
   339     const Decimal& lhs = *this;
   340     const Sign lhsSign = lhs.sign();
   341     const Sign rhsSign = rhs.sign();
   343     SpecialValueHandler handler(lhs, rhs);
   344     switch (handler.handle()) {
   345     case SpecialValueHandler::BothFinite:
   346         break;
   348     case SpecialValueHandler::BothInfinity:
   349         return lhsSign == rhsSign ? lhs : nan();
   351     case SpecialValueHandler::EitherNaN:
   352         return handler.value();
   354     case SpecialValueHandler::LHSIsInfinity:
   355         return lhs;
   357     case SpecialValueHandler::RHSIsInfinity:
   358         return rhs;
   359     }
   361     const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
   363     const uint64_t result = lhsSign == rhsSign
   364         ? alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient
   365         : alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient;
   367     if (lhsSign == Negative && rhsSign == Positive && !result)
   368         return Decimal(Positive, alignedOperands.exponent, 0);
   370     return static_cast<int64_t>(result) >= 0
   371         ? Decimal(lhsSign, alignedOperands.exponent, result)
   372         : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
   373 }
   375 Decimal Decimal::operator-(const Decimal& rhs) const
   376 {
   377     const Decimal& lhs = *this;
   378     const Sign lhsSign = lhs.sign();
   379     const Sign rhsSign = rhs.sign();
   381     SpecialValueHandler handler(lhs, rhs);
   382     switch (handler.handle()) {
   383     case SpecialValueHandler::BothFinite:
   384         break;
   386     case SpecialValueHandler::BothInfinity:
   387         return lhsSign == rhsSign ? nan() : lhs;
   389     case SpecialValueHandler::EitherNaN:
   390         return handler.value();
   392     case SpecialValueHandler::LHSIsInfinity:
   393         return lhs;
   395     case SpecialValueHandler::RHSIsInfinity:
   396         return infinity(invertSign(rhsSign));
   397     }
   399     const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
   401     const uint64_t result = lhsSign == rhsSign
   402         ? alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient
   403         : alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient;
   405     if (lhsSign == Negative && rhsSign == Negative && !result)
   406         return Decimal(Positive, alignedOperands.exponent, 0);
   408     return static_cast<int64_t>(result) >= 0
   409         ? Decimal(lhsSign, alignedOperands.exponent, result)
   410         : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
   411 }
   413 Decimal Decimal::operator*(const Decimal& rhs) const
   414 {
   415     const Decimal& lhs = *this;
   416     const Sign lhsSign = lhs.sign();
   417     const Sign rhsSign = rhs.sign();
   418     const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
   420     SpecialValueHandler handler(lhs, rhs);
   421     switch (handler.handle()) {
   422     case SpecialValueHandler::BothFinite: {
   423         const uint64_t lhsCoefficient = lhs.m_data.coefficient();
   424         const uint64_t rhsCoefficient = rhs.m_data.coefficient();
   425         int resultExponent = lhs.exponent() + rhs.exponent();
   426         UInt128 work(UInt128::multiply(lhsCoefficient, rhsCoefficient));
   427         while (work.high()) {
   428             work /= 10;
   429             ++resultExponent;
   430         }
   431         return Decimal(resultSign, resultExponent, work.low());
   432     }
   434     case SpecialValueHandler::BothInfinity:
   435         return infinity(resultSign);
   437     case SpecialValueHandler::EitherNaN:
   438         return handler.value();
   440     case SpecialValueHandler::LHSIsInfinity:
   441         return rhs.isZero() ? nan() : infinity(resultSign);
   443     case SpecialValueHandler::RHSIsInfinity:
   444         return lhs.isZero() ? nan() : infinity(resultSign);
   445     }
   447     ASSERT_NOT_REACHED();
   448     return nan();
   449 }
   451 Decimal Decimal::operator/(const Decimal& rhs) const
   452 {
   453     const Decimal& lhs = *this;
   454     const Sign lhsSign = lhs.sign();
   455     const Sign rhsSign = rhs.sign();
   456     const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
   458     SpecialValueHandler handler(lhs, rhs);
   459     switch (handler.handle()) {
   460     case SpecialValueHandler::BothFinite:
   461         break;
   463     case SpecialValueHandler::BothInfinity:
   464         return nan();
   466     case SpecialValueHandler::EitherNaN:
   467         return handler.value();
   469     case SpecialValueHandler::LHSIsInfinity:
   470         return infinity(resultSign);
   472     case SpecialValueHandler::RHSIsInfinity:
   473         return zero(resultSign);
   474     }
   476     ASSERT(lhs.isFinite());
   477     ASSERT(rhs.isFinite());
   479     if (rhs.isZero())
   480         return lhs.isZero() ? nan() : infinity(resultSign);
   482     int resultExponent = lhs.exponent() - rhs.exponent();
   484     if (lhs.isZero())
   485         return Decimal(resultSign, resultExponent, 0);
   487     uint64_t remainder = lhs.m_data.coefficient();
   488     const uint64_t divisor = rhs.m_data.coefficient();
   489     uint64_t result = 0;
   490     while (result < MaxCoefficient / 100) {
   491         while (remainder < divisor) {
   492             remainder *= 10;
   493             result *= 10;
   494             --resultExponent;
   495         }
   496         result += remainder / divisor;
   497         remainder %= divisor;
   498         if (!remainder)
   499             break;
   500     }
   502     if (remainder > divisor / 2)
   503         ++result;
   505     return Decimal(resultSign, resultExponent, result);
   506 }
   508 bool Decimal::operator==(const Decimal& rhs) const
   509 {
   510     if (isNaN() || rhs.isNaN())
   511         return false;
   512     return m_data == rhs.m_data || compareTo(rhs).isZero();
   513 }
   515 bool Decimal::operator!=(const Decimal& rhs) const
   516 {
   517     if (isNaN() || rhs.isNaN())
   518         return true;
   519     if (m_data == rhs.m_data)
   520         return false;
   521     const Decimal result = compareTo(rhs);
   522     if (result.isNaN())
   523         return false;
   524     return !result.isZero();
   525 }
   527 bool Decimal::operator<(const Decimal& rhs) const
   528 {
   529     const Decimal result = compareTo(rhs);
   530     if (result.isNaN())
   531         return false;
   532     return !result.isZero() && result.isNegative();
   533 }
   535 bool Decimal::operator<=(const Decimal& rhs) const
   536 {
   537     if (isNaN() || rhs.isNaN())
   538         return false;
   539     if (m_data == rhs.m_data)
   540         return true;
   541     const Decimal result = compareTo(rhs);
   542     if (result.isNaN())
   543         return false;
   544     return result.isZero() || result.isNegative();
   545 }
   547 bool Decimal::operator>(const Decimal& rhs) const
   548 {
   549     const Decimal result = compareTo(rhs);
   550     if (result.isNaN())
   551         return false;
   552     return !result.isZero() && result.isPositive();
   553 }
   555 bool Decimal::operator>=(const Decimal& rhs) const
   556 {
   557     if (isNaN() || rhs.isNaN())
   558         return false;
   559     if (m_data == rhs.m_data)
   560         return true;
   561     const Decimal result = compareTo(rhs);
   562     if (result.isNaN())
   563         return false;
   564     return result.isZero() || !result.isNegative();
   565 }
   567 Decimal Decimal::abs() const
   568 {
   569     Decimal result(*this);
   570     result.m_data.setSign(Positive);
   571     return result;
   572 }
   574 Decimal::AlignedOperands Decimal::alignOperands(const Decimal& lhs, const Decimal& rhs)
   575 {
   576     ASSERT(lhs.isFinite());
   577     ASSERT(rhs.isFinite());
   579     const int lhsExponent = lhs.exponent();
   580     const int rhsExponent = rhs.exponent();
   581     int exponent = std::min(lhsExponent, rhsExponent);
   582     uint64_t lhsCoefficient = lhs.m_data.coefficient();
   583     uint64_t rhsCoefficient = rhs.m_data.coefficient();
   585     if (lhsExponent > rhsExponent) {
   586         const int numberOfLHSDigits = countDigits(lhsCoefficient);
   587         if (numberOfLHSDigits) {
   588             const int lhsShiftAmount = lhsExponent - rhsExponent;
   589             const int overflow = numberOfLHSDigits + lhsShiftAmount - Precision;
   590             if (overflow <= 0)
   591                 lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount);
   592             else {
   593                 lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount - overflow);
   594                 rhsCoefficient = scaleDown(rhsCoefficient, overflow);
   595                 exponent += overflow;
   596             }
   597         }
   599     } else if (lhsExponent < rhsExponent) {
   600         const int numberOfRHSDigits = countDigits(rhsCoefficient);
   601         if (numberOfRHSDigits) {
   602             const int rhsShiftAmount = rhsExponent - lhsExponent;
   603             const int overflow = numberOfRHSDigits + rhsShiftAmount - Precision;
   604             if (overflow <= 0)
   605                 rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount);
   606             else {
   607                 rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount - overflow);
   608                 lhsCoefficient = scaleDown(lhsCoefficient, overflow);
   609                 exponent += overflow;
   610             }
   611         }
   612     }
   614     AlignedOperands alignedOperands;
   615     alignedOperands.exponent = exponent;
   616     alignedOperands.lhsCoefficient = lhsCoefficient;
   617     alignedOperands.rhsCoefficient = rhsCoefficient;
   618     return alignedOperands;
   619 }
   621 // Round toward positive infinity.
   622 // Note: Mac ports defines ceil(x) as wtf_ceil(x), so we can't use name "ceil" here.
   623 Decimal Decimal::ceiling() const
   624 {
   625     if (isSpecial())
   626         return *this;
   628     if (exponent() >= 0)
   629         return *this;
   631     uint64_t coefficient = m_data.coefficient();
   632     const int numberOfDigits = countDigits(coefficient);
   633     const int numberOfDropDigits = -exponent();
   634     if (numberOfDigits < numberOfDropDigits)
   635         return isPositive() ? Decimal(1) : zero(Positive);
   637     uint64_t result = scaleDown(coefficient, numberOfDropDigits);
   638     uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits);
   639     if (droppedDigits && isPositive())
   640         result += 1;
   641     return Decimal(sign(), 0, result);
   642 }
   644 Decimal Decimal::compareTo(const Decimal& rhs) const
   645 {
   646     const Decimal result(*this - rhs);
   647     switch (result.m_data.formatClass()) {
   648     case EncodedData::ClassInfinity:
   649         return result.isNegative() ? Decimal(-1) : Decimal(1);
   651     case EncodedData::ClassNaN:
   652     case EncodedData::ClassNormal:
   653         return result;
   655     case EncodedData::ClassZero:
   656         return zero(Positive);
   658     default:
   659         ASSERT_NOT_REACHED();
   660         return nan();
   661     }
   662 }
   664 // Round toward negative infinity.
   665 Decimal Decimal::floor() const
   666 {
   667     if (isSpecial())
   668         return *this;
   670     if (exponent() >= 0)
   671         return *this;
   673     uint64_t coefficient = m_data.coefficient();
   674     const int numberOfDigits = countDigits(coefficient);
   675     const int numberOfDropDigits = -exponent();
   676     if (numberOfDigits < numberOfDropDigits)
   677         return isPositive() ? zero(Positive) : Decimal(-1);
   679     uint64_t result = scaleDown(coefficient, numberOfDropDigits);
   680     uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits);
   681     if (droppedDigits && isNegative()) {
   682         result += 1;
   683     }
   684     return Decimal(sign(), 0, result);
   685 }
   687 Decimal Decimal::fromDouble(double doubleValue)
   688 {
   689     if (std::isfinite(doubleValue))
   690         return fromString(mozToString(doubleValue));
   692     if (std::isinf(doubleValue))
   693         return infinity(doubleValue < 0 ? Negative : Positive);
   695     return nan();
   696 }
   698 Decimal Decimal::fromString(const String& str)
   699 {
   700     int exponent = 0;
   701     Sign exponentSign = Positive;
   702     int numberOfDigits = 0;
   703     int numberOfDigitsAfterDot = 0;
   704     int numberOfExtraDigits = 0;
   705     Sign sign = Positive;
   707     enum {
   708         StateDigit,
   709         StateDot,
   710         StateDotDigit,
   711         StateE,
   712         StateEDigit,
   713         StateESign,
   714         StateSign,
   715         StateStart,
   716         StateZero,
   717     } state = StateStart;
   719 #define HandleCharAndBreak(expected, nextState) \
   720     if (ch == expected) { \
   721         state = nextState; \
   722         break; \
   723     }
   725 #define HandleTwoCharsAndBreak(expected1, expected2, nextState) \
   726     if (ch == expected1 || ch == expected2) { \
   727         state = nextState; \
   728         break; \
   729     }
   731     uint64_t accumulator = 0;
   732     for (unsigned index = 0; index < str.length(); ++index) {
   733         const int ch = str[index];
   734         switch (state) {
   735         case StateDigit:
   736             if (ch >= '0' && ch <= '9') {
   737                 if (numberOfDigits < Precision) {
   738                     ++numberOfDigits;
   739                     accumulator *= 10;
   740                     accumulator += ch - '0';
   741                 } else
   742                     ++numberOfExtraDigits;
   743                 break;
   744             }
   746             HandleCharAndBreak('.', StateDot);
   747             HandleTwoCharsAndBreak('E', 'e', StateE);
   748             return nan();
   750         case StateDot:
   751             if (ch >= '0' && ch <= '9') {
   752                 if (numberOfDigits < Precision) {
   753                     ++numberOfDigits;
   754                     ++numberOfDigitsAfterDot;
   755                     accumulator *= 10;
   756                     accumulator += ch - '0';
   757                 }
   758                 state = StateDotDigit;
   759                 break;
   760             }
   762         case StateDotDigit:
   763             if (ch >= '0' && ch <= '9') {
   764                 if (numberOfDigits < Precision) {
   765                     ++numberOfDigits;
   766                     ++numberOfDigitsAfterDot;
   767                     accumulator *= 10;
   768                     accumulator += ch - '0';
   769                 }
   770                 break;
   771             }
   773             HandleTwoCharsAndBreak('E', 'e', StateE);
   774             return nan();
   776         case StateE:
   777             if (ch == '+') {
   778                 exponentSign = Positive;
   779                 state = StateESign;
   780                 break;
   781             }
   783             if (ch == '-') {
   784                 exponentSign = Negative;
   785                 state = StateESign;
   786                 break;
   787             }
   789             if (ch >= '0' && ch <= '9') {
   790                 exponent = ch - '0';
   791                 state = StateEDigit;
   792                 break;
   793             }
   795             return nan();
   797         case StateEDigit:
   798             if (ch >= '0' && ch <= '9') {
   799                 exponent *= 10;
   800                 exponent += ch - '0';
   801                 if (exponent > ExponentMax + Precision) {
   802                     if (accumulator)
   803                         return exponentSign == Negative ? zero(Positive) : infinity(sign);
   804                     return zero(sign);
   805                 }
   806                 state = StateEDigit;
   807                 break;
   808             }
   810             return nan();
   812         case StateESign:
   813             if (ch >= '0' && ch <= '9') {
   814                 exponent = ch - '0';
   815                 state = StateEDigit;
   816                 break;
   817             }
   819             return nan();
   821         case StateSign:
   822             if (ch >= '1' && ch <= '9') {
   823                 accumulator = ch - '0';
   824                 numberOfDigits = 1;
   825                 state = StateDigit;
   826                 break;
   827             }
   829             HandleCharAndBreak('0', StateZero);
   830             return nan();
   832         case StateStart:
   833             if (ch >= '1' && ch <= '9') {
   834                 accumulator = ch - '0';
   835                 numberOfDigits = 1;
   836                 state = StateDigit;
   837                 break;
   838             }
   840             if (ch == '-') {
   841                 sign = Negative;
   842                 state = StateSign;
   843                 break;
   844             }
   846             if (ch == '+') {
   847                 sign = Positive;
   848                 state = StateSign;
   849                 break;
   850             }
   852             HandleCharAndBreak('0', StateZero);
   853             HandleCharAndBreak('.', StateDot);
   854             return nan();
   856         case StateZero:
   857             if (ch == '0')
   858                 break;
   860             if (ch >= '1' && ch <= '9') {
   861                 accumulator = ch - '0';
   862                 numberOfDigits = 1;
   863                 state = StateDigit;
   864                 break;
   865             }
   867             HandleCharAndBreak('.', StateDot);
   868             HandleTwoCharsAndBreak('E', 'e', StateE);
   869             return nan();
   871         default:
   872             ASSERT_NOT_REACHED();
   873             return nan();
   874         }
   875     }
   877     if (state == StateZero)
   878         return zero(sign);
   880     if (state == StateDigit || state == StateEDigit || state == StateDotDigit) {
   881         int resultExponent = exponent * (exponentSign == Negative ? -1 : 1) - numberOfDigitsAfterDot + numberOfExtraDigits;
   882         if (resultExponent < ExponentMin)
   883             return zero(Positive);
   885         const int overflow = resultExponent - ExponentMax + 1;
   886         if (overflow > 0) {
   887             if (overflow + numberOfDigits - numberOfDigitsAfterDot > Precision)
   888                 return infinity(sign);
   889             accumulator = scaleUp(accumulator, overflow);
   890             resultExponent -= overflow;
   891         }
   893         return Decimal(sign, resultExponent, accumulator);
   894     }
   896     return nan();
   897 }
   899 Decimal Decimal::infinity(const Sign sign)
   900 {
   901     return Decimal(EncodedData(sign, EncodedData::ClassInfinity));
   902 }
   904 Decimal Decimal::nan()
   905 {
   906     return Decimal(EncodedData(Positive, EncodedData::ClassNaN));
   907 }
   909 Decimal Decimal::remainder(const Decimal& rhs) const
   910 {
   911     const Decimal quotient = *this / rhs;
   912     return quotient.isSpecial() ? quotient : *this - (quotient.isNegative() ? quotient.ceiling() : quotient.floor()) * rhs;
   913 }
   915 Decimal Decimal::round() const
   916 {
   917     if (isSpecial())
   918         return *this;
   920     if (exponent() >= 0)
   921         return *this;
   923     uint64_t result = m_data.coefficient();
   924     const int numberOfDigits = countDigits(result);
   925     const int numberOfDropDigits = -exponent();
   926     if (numberOfDigits < numberOfDropDigits)
   927         return zero(Positive);
   929     // We're implementing round-half-away-from-zero, so we only need the one
   930     // (the most significant) fractional digit:
   931     result = scaleDown(result, numberOfDropDigits - 1);
   932     if (result % 10 >= 5)
   933         result += 10;
   934     result /= 10;
   935     return Decimal(sign(), 0, result);
   936 }
   938 double Decimal::toDouble() const
   939 {
   940     if (isFinite()) {
   941         bool valid;
   942         const double doubleValue = mozToDouble(toString(), &valid);
   943         return valid ? doubleValue : std::numeric_limits<double>::quiet_NaN();
   944     }
   946     if (isInfinity())
   947         return isNegative() ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
   949     return std::numeric_limits<double>::quiet_NaN();
   950 }
   952 String Decimal::toString() const
   953 {
   954     switch (m_data.formatClass()) {
   955     case EncodedData::ClassInfinity:
   956         return sign() ? "-Infinity" : "Infinity";
   958     case EncodedData::ClassNaN:
   959         return "NaN";
   961     case EncodedData::ClassNormal:
   962     case EncodedData::ClassZero:
   963         break;
   965     default:
   966         ASSERT_NOT_REACHED();
   967         return "";
   968     }
   970     StringBuilder builder;
   971     if (sign())
   972         builder.append('-');
   974     int originalExponent = exponent();
   975     uint64_t coefficient = m_data.coefficient();
   977     if (originalExponent < 0) {
   978         const int maxDigits = DBL_DIG;
   979         uint64_t lastDigit = 0;
   980         while (countDigits(coefficient) > maxDigits) {
   981             lastDigit = coefficient % 10;
   982             coefficient /= 10;
   983             ++originalExponent;
   984         }
   986         if (lastDigit >= 5)
   987             ++coefficient;
   989         while (originalExponent < 0 && coefficient && !(coefficient % 10)) {
   990             coefficient /= 10;
   991             ++originalExponent;
   992         }
   993     }
   995     const String digits = mozToString(coefficient);
   996     int coefficientLength = static_cast<int>(digits.length());
   997     const int adjustedExponent = originalExponent + coefficientLength - 1;
   998     if (originalExponent <= 0 && adjustedExponent >= -6) {
   999         if (!originalExponent) {
  1000             builder.append(digits);
  1001             return builder.toString();
  1004         if (adjustedExponent >= 0) {
  1005             for (int i = 0; i < coefficientLength; ++i) {
  1006                 builder.append(digits[i]);
  1007                 if (i == adjustedExponent)
  1008                     builder.append('.');
  1010             return builder.toString();
  1013         builder.appendLiteral("0.");
  1014         for (int i = adjustedExponent + 1; i < 0; ++i)
  1015             builder.append('0');
  1017         builder.append(digits);
  1019     } else {
  1020         builder.append(digits[0]);
  1021         while (coefficientLength >= 2 && digits[coefficientLength - 1] == '0')
  1022             --coefficientLength;
  1023         if (coefficientLength >= 2) {
  1024             builder.append('.');
  1025             for (int i = 1; i < coefficientLength; ++i)
  1026                 builder.append(digits[i]);
  1029         if (adjustedExponent) {
  1030             builder.append(adjustedExponent < 0 ? "e" : "e+");
  1031             builder.appendNumber(adjustedExponent);
  1034     return builder.toString();
  1037 bool Decimal::toString(char* strBuf, size_t bufLength) const
  1039   ASSERT(bufLength > 0);
  1040   String str = toString();
  1041   size_t length = str.copy(strBuf, bufLength);
  1042   if (length < bufLength) {
  1043     strBuf[length] = '\0';
  1044     return true;
  1046   strBuf[bufLength - 1] = '\0';
  1047   return false;
  1050 Decimal Decimal::zero(Sign sign)
  1052     return Decimal(EncodedData(sign, EncodedData::ClassZero));
  1055 } // namespace WebCore

mercurial