1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051 |
- /*
- * 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"
- using namespace moz_decimal_utils;
- #include <algorithm>
- #include <float.h>
- namespace blink {
- namespace DecimalPrivate {
- static int const ExponentMax = 1023;
- static int const ExponentMin = -1023;
- static int const Precision = 18;
- static const uint64_t MaxCoefficient = UINT64_C(0xDE0B6B3A763FFFF); // 999999999999999999 == 18 9's
- // This class handles Decimal special values.
- class SpecialValueHandler {
- STACK_ALLOCATED();
- 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<uint32_t>(x >> 32); }
- static uint32_t lowUInt32(uint64_t x) { return static_cast<uint32_t>(x & ((static_cast<uint64_t>(1) << 32) - 1)); }
- static uint64_t makeUInt64(uint32_t low, uint32_t high) { return low | (static_cast<uint64_t>(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<uint32_t>(work % divisor);
- quotient[i] = static_cast<uint32_t>(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<uint64_t>::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<int16_t>(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<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(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<int64_t>(result) >= 0
- ? Decimal(lhsSign, alignedOperands.exponent, result)
- : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(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<int64_t>(result) >= 0
- ? Decimal(lhsSign, alignedOperands.exponent, result)
- : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(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;
- for (;;) {
- while (remainder < divisor && result < MaxCoefficient / 10) {
- remainder *= 10;
- result *= 10;
- --resultExponent;
- }
- if (remainder < divisor)
- break;
- uint64_t quotient = remainder / divisor;
- if (result > MaxCoefficient - quotient)
- break;
- result += quotient;
- 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;
- }
- static bool isMultiplePowersOfTen(uint64_t coefficient, int n)
- {
- return !coefficient || !(coefficient % scaleUp(1, n));
- }
- // Round toward positive infinity.
- Decimal Decimal::ceil() 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 isPositive() ? Decimal(1) : zero(Positive);
- result = scaleDown(result, numberOfDropDigits);
- if (isPositive() && !isMultiplePowersOfTen(m_data.coefficient(), numberOfDropDigits))
- ++result;
- 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 result = m_data.coefficient();
- const int numberOfDigits = countDigits(result);
- const int numberOfDropDigits = -exponent();
- if (numberOfDigits < numberOfDropDigits)
- return isPositive() ? zero(Positive) : Decimal(-1);
- result = scaleDown(result, numberOfDropDigits);
- if (isNegative() && !isMultiplePowersOfTen(m_data.coefficient(), numberOfDropDigits))
- ++result;
- 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:
- case StateDotDigit:
- if (ch >= '0' && ch <= '9') {
- if (numberOfDigits < Precision) {
- ++numberOfDigits;
- ++numberOfDigitsAfterDot;
- accumulator *= 10;
- accumulator += ch - '0';
- }
- state = StateDotDigit;
- 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.ceil() : 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);
- 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<double>::quiet_NaN();
- }
- if (isInfinity())
- return isNegative() ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
- return std::numeric_limits<double>::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<int>(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 blink
|