| /* |
| * 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 "third_party/blink/renderer/platform/wtf/decimal.h" |
| |
| #include <algorithm> |
| #include <cfloat> |
| |
| #include "base/macros.h" |
| #include "base/notreached.h" |
| #include "third_party/blink/renderer/platform/wtf/allocator/allocator.h" |
| #include "third_party/blink/renderer/platform/wtf/math_extras.h" |
| #include "third_party/blink/renderer/platform/wtf/text/string_builder.h" |
| |
| namespace blink { |
| |
| namespace { |
| |
| constexpr int kExponentMax = 1023; |
| constexpr int kExponentMin = -1023; |
| constexpr int kPrecision = 18; |
| |
| constexpr uint64_t kMaxCoefficient = |
| UINT64_C(0xDE0B6B3A763FFFF); // 999999999999999999 == 18 9's |
| |
| // This class handles Decimal special values. |
| class SpecialValueHandler { |
| STACK_ALLOCATED(); |
| |
| public: |
| enum HandleResult { |
| kBothFinite, |
| kBothInfinity, |
| kEitherNaN, |
| kLHSIsInfinity, |
| kRHSIsInfinity, |
| }; |
| |
| SpecialValueHandler(const Decimal& lhs, const Decimal& rhs); |
| HandleResult Handle(); |
| Decimal Value() const; |
| |
| private: |
| enum Result { |
| kResultIsLHS, |
| kResultIsRHS, |
| kResultIsUnknown, |
| }; |
| |
| const Decimal& lhs_; |
| const Decimal& rhs_; |
| Result result_ = kResultIsUnknown; |
| |
| DISALLOW_COPY_AND_ASSIGN(SpecialValueHandler); |
| }; |
| |
| SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs) |
| : lhs_(lhs), rhs_(rhs) {} |
| |
| SpecialValueHandler::HandleResult SpecialValueHandler::Handle() { |
| if (lhs_.IsFinite() && rhs_.IsFinite()) |
| return kBothFinite; |
| |
| if (lhs_.IsNaN()) { |
| result_ = kResultIsLHS; |
| return kEitherNaN; |
| } |
| |
| if (rhs_.IsNaN()) { |
| result_ = kResultIsRHS; |
| return kEitherNaN; |
| } |
| |
| if (lhs_.IsInfinity()) |
| return rhs_.IsInfinity() ? kBothInfinity : kLHSIsInfinity; |
| |
| DCHECK(rhs_.IsInfinity()); |
| return kRHSIsInfinity; |
| } |
| |
| Decimal SpecialValueHandler::Value() const { |
| DCHECK(result_ == kResultIsLHS || result_ == kResultIsRHS); |
| return (result_ == kResultIsLHS) ? lhs_ : rhs_; |
| } |
| |
| // This class is used for 128 bit unsigned integer arithmetic. |
| class UInt128 { |
| STACK_ALLOCATED(); |
| |
| public: |
| UInt128(uint64_t low, uint64_t high) : high_(high), low_(low) {} |
| |
| UInt128& operator/=(uint32_t); |
| |
| uint64_t High() const { return high_; } |
| uint64_t Low() const { return 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 high_; |
| uint64_t low_; |
| }; |
| |
| UInt128& UInt128::operator/=(const uint32_t divisor) { |
| DCHECK(divisor); |
| |
| if (!high_) { |
| low_ /= divisor; |
| return *this; |
| } |
| |
| uint32_t dividend[4]; |
| dividend[0] = LowUInt32(low_); |
| dividend[1] = HighUInt32(low_); |
| dividend[2] = LowUInt32(high_); |
| dividend[3] = HighUInt32(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); |
| } |
| low_ = MakeUInt64(quotient[0], quotient[1]); |
| 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 u_low = LowUInt32(u); |
| const uint64_t u_high = HighUInt32(u); |
| const uint64_t v_low = LowUInt32(v); |
| const uint64_t v_high = HighUInt32(v); |
| const uint64_t partial_product = u_high * v_low + HighUInt32(u_low * v_low); |
| return u_high * v_high + HighUInt32(partial_product) + |
| HighUInt32(u_low * v_high + LowUInt32(partial_product)); |
| } |
| |
| static int CountDigits(uint64_t x) { |
| int number_of_digits = 0; |
| for (uint64_t power_of_ten = 1; x >= power_of_ten; power_of_ten *= 10) { |
| ++number_of_digits; |
| if (power_of_ten >= std::numeric_limits<uint64_t>::max() / 10) |
| break; |
| } |
| return number_of_digits; |
| } |
| |
| static uint64_t ScaleDown(uint64_t x, int n) { |
| DCHECK_GE(n, 0); |
| while (n > 0 && x) { |
| x /= 10; |
| --n; |
| } |
| return x; |
| } |
| |
| static uint64_t ScaleUp(uint64_t x, int n) { |
| DCHECK_GE(n, 0); |
| DCHECK_LE(n, kPrecision); |
| |
| 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 |
| |
| Decimal::EncodedData::EncodedData(Sign sign, FormatClass format_class) |
| : coefficient_(0), exponent_(0), format_class_(format_class), sign_(sign) {} |
| |
| Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient) |
| : format_class_(coefficient ? kClassNormal : kClassZero), sign_(sign) { |
| if (exponent >= kExponentMin && exponent <= kExponentMax) { |
| while (coefficient > kMaxCoefficient) { |
| coefficient /= 10; |
| ++exponent; |
| } |
| } |
| |
| if (exponent > kExponentMax) { |
| coefficient_ = 0; |
| exponent_ = 0; |
| format_class_ = kClassInfinity; |
| return; |
| } |
| |
| if (exponent < kExponentMin) { |
| coefficient_ = 0; |
| exponent_ = 0; |
| format_class_ = kClassZero; |
| return; |
| } |
| |
| coefficient_ = coefficient; |
| exponent_ = static_cast<int16_t>(exponent); |
| } |
| |
| bool Decimal::EncodedData::operator==(const EncodedData& another) const { |
| return sign_ == another.sign_ && format_class_ == another.format_class_ && |
| exponent_ == another.exponent_ && coefficient_ == another.coefficient_; |
| } |
| |
| Decimal::Decimal(int32_t i32) |
| : data_(i32 < 0 ? kNegative : kPositive, |
| 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) |
| : data_(sign, exponent, coefficient) {} |
| |
| Decimal::Decimal(const EncodedData& data) : data_(data) {} |
| |
| Decimal::Decimal(const Decimal& other) = default; |
| |
| Decimal& Decimal::operator=(const Decimal& other) = default; |
| |
| Decimal& Decimal::operator+=(const Decimal& other) { |
| data_ = (*this + other).data_; |
| return *this; |
| } |
| |
| Decimal& Decimal::operator-=(const Decimal& other) { |
| data_ = (*this - other).data_; |
| return *this; |
| } |
| |
| Decimal& Decimal::operator*=(const Decimal& other) { |
| data_ = (*this * other).data_; |
| return *this; |
| } |
| |
| Decimal& Decimal::operator/=(const Decimal& other) { |
| data_ = (*this / other).data_; |
| return *this; |
| } |
| |
| Decimal Decimal::operator-() const { |
| if (IsNaN()) |
| return *this; |
| |
| Decimal result(*this); |
| result.data_.SetSign(InvertSign(data_.GetSign())); |
| return result; |
| } |
| |
| Decimal Decimal::operator+(const Decimal& rhs) const { |
| const Decimal& lhs = *this; |
| const Sign lhs_sign = lhs.GetSign(); |
| const Sign rhs_sign = rhs.GetSign(); |
| |
| SpecialValueHandler handler(lhs, rhs); |
| switch (handler.Handle()) { |
| case SpecialValueHandler::kBothFinite: |
| break; |
| |
| case SpecialValueHandler::kBothInfinity: |
| return lhs_sign == rhs_sign ? lhs : Nan(); |
| |
| case SpecialValueHandler::kEitherNaN: |
| return handler.Value(); |
| |
| case SpecialValueHandler::kLHSIsInfinity: |
| return lhs; |
| |
| case SpecialValueHandler::kRHSIsInfinity: |
| return rhs; |
| } |
| |
| const AlignedOperands aligned_operands = AlignOperands(lhs, rhs); |
| |
| const uint64_t result = |
| lhs_sign == rhs_sign |
| ? aligned_operands.lhs_coefficient + aligned_operands.rhs_coefficient |
| : aligned_operands.lhs_coefficient - aligned_operands.rhs_coefficient; |
| |
| if (lhs_sign == kNegative && rhs_sign == kPositive && !result) |
| return Decimal(kPositive, aligned_operands.exponent, 0); |
| |
| return static_cast<int64_t>(result) >= 0 |
| ? Decimal(lhs_sign, aligned_operands.exponent, result) |
| : Decimal(InvertSign(lhs_sign), aligned_operands.exponent, |
| -static_cast<int64_t>(result)); |
| } |
| |
| Decimal Decimal::operator-(const Decimal& rhs) const { |
| const Decimal& lhs = *this; |
| const Sign lhs_sign = lhs.GetSign(); |
| const Sign rhs_sign = rhs.GetSign(); |
| |
| SpecialValueHandler handler(lhs, rhs); |
| switch (handler.Handle()) { |
| case SpecialValueHandler::kBothFinite: |
| break; |
| |
| case SpecialValueHandler::kBothInfinity: |
| return lhs_sign == rhs_sign ? Nan() : lhs; |
| |
| case SpecialValueHandler::kEitherNaN: |
| return handler.Value(); |
| |
| case SpecialValueHandler::kLHSIsInfinity: |
| return lhs; |
| |
| case SpecialValueHandler::kRHSIsInfinity: |
| return Infinity(InvertSign(rhs_sign)); |
| } |
| |
| const AlignedOperands aligned_operands = AlignOperands(lhs, rhs); |
| |
| const uint64_t result = |
| lhs_sign == rhs_sign |
| ? aligned_operands.lhs_coefficient - aligned_operands.rhs_coefficient |
| : aligned_operands.lhs_coefficient + aligned_operands.rhs_coefficient; |
| |
| if (lhs_sign == kNegative && rhs_sign == kNegative && !result) |
| return Decimal(kPositive, aligned_operands.exponent, 0); |
| |
| return static_cast<int64_t>(result) >= 0 |
| ? Decimal(lhs_sign, aligned_operands.exponent, result) |
| : Decimal(InvertSign(lhs_sign), aligned_operands.exponent, |
| -static_cast<int64_t>(result)); |
| } |
| |
| Decimal Decimal::operator*(const Decimal& rhs) const { |
| const Decimal& lhs = *this; |
| const Sign lhs_sign = lhs.GetSign(); |
| const Sign rhs_sign = rhs.GetSign(); |
| const Sign result_sign = lhs_sign == rhs_sign ? kPositive : kNegative; |
| |
| SpecialValueHandler handler(lhs, rhs); |
| switch (handler.Handle()) { |
| case SpecialValueHandler::kBothFinite: { |
| const uint64_t lhs_coefficient = lhs.data_.Coefficient(); |
| const uint64_t rhs_coefficient = rhs.data_.Coefficient(); |
| int result_exponent = lhs.Exponent() + rhs.Exponent(); |
| UInt128 work(UInt128::Multiply(lhs_coefficient, rhs_coefficient)); |
| while (work.High()) { |
| work /= 10; |
| ++result_exponent; |
| } |
| return Decimal(result_sign, result_exponent, work.Low()); |
| } |
| |
| case SpecialValueHandler::kBothInfinity: |
| return Infinity(result_sign); |
| |
| case SpecialValueHandler::kEitherNaN: |
| return handler.Value(); |
| |
| case SpecialValueHandler::kLHSIsInfinity: |
| return rhs.IsZero() ? Nan() : Infinity(result_sign); |
| |
| case SpecialValueHandler::kRHSIsInfinity: |
| return lhs.IsZero() ? Nan() : Infinity(result_sign); |
| } |
| |
| NOTREACHED(); |
| return Nan(); |
| } |
| |
| Decimal Decimal::operator/(const Decimal& rhs) const { |
| const Decimal& lhs = *this; |
| const Sign lhs_sign = lhs.GetSign(); |
| const Sign rhs_sign = rhs.GetSign(); |
| const Sign result_sign = lhs_sign == rhs_sign ? kPositive : kNegative; |
| |
| SpecialValueHandler handler(lhs, rhs); |
| switch (handler.Handle()) { |
| case SpecialValueHandler::kBothFinite: |
| break; |
| |
| case SpecialValueHandler::kBothInfinity: |
| return Nan(); |
| |
| case SpecialValueHandler::kEitherNaN: |
| return handler.Value(); |
| |
| case SpecialValueHandler::kLHSIsInfinity: |
| return Infinity(result_sign); |
| |
| case SpecialValueHandler::kRHSIsInfinity: |
| return Zero(result_sign); |
| } |
| |
| DCHECK(lhs.IsFinite()); |
| DCHECK(rhs.IsFinite()); |
| |
| if (rhs.IsZero()) |
| return lhs.IsZero() ? Nan() : Infinity(result_sign); |
| |
| int result_exponent = lhs.Exponent() - rhs.Exponent(); |
| |
| if (lhs.IsZero()) |
| return Decimal(result_sign, result_exponent, 0); |
| |
| uint64_t remainder = lhs.data_.Coefficient(); |
| const uint64_t divisor = rhs.data_.Coefficient(); |
| uint64_t result = 0; |
| for (;;) { |
| while (remainder < divisor && result < kMaxCoefficient / 10) { |
| remainder *= 10; |
| result *= 10; |
| --result_exponent; |
| } |
| if (remainder < divisor) |
| break; |
| uint64_t quotient = remainder / divisor; |
| if (result > kMaxCoefficient - quotient) |
| break; |
| result += quotient; |
| remainder %= divisor; |
| if (!remainder) |
| break; |
| } |
| |
| if (remainder > divisor / 2) |
| ++result; |
| |
| return Decimal(result_sign, result_exponent, result); |
| } |
| |
| bool Decimal::operator==(const Decimal& rhs) const { |
| return data_ == rhs.data_ || CompareTo(rhs).IsZero(); |
| } |
| |
| bool Decimal::operator!=(const Decimal& rhs) const { |
| if (data_ == rhs.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 (data_ == rhs.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 (data_ == rhs.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.data_.SetSign(kPositive); |
| return result; |
| } |
| |
| Decimal::AlignedOperands Decimal::AlignOperands(const Decimal& lhs, |
| const Decimal& rhs) { |
| DCHECK(lhs.IsFinite()); |
| DCHECK(rhs.IsFinite()); |
| |
| const int lhs_exponent = lhs.Exponent(); |
| const int rhs_exponent = rhs.Exponent(); |
| int exponent = std::min(lhs_exponent, rhs_exponent); |
| uint64_t lhs_coefficient = lhs.data_.Coefficient(); |
| uint64_t rhs_coefficient = rhs.data_.Coefficient(); |
| |
| if (lhs_exponent > rhs_exponent) { |
| const int number_of_lhs_digits = CountDigits(lhs_coefficient); |
| if (number_of_lhs_digits) { |
| const int lhs_shift_amount = lhs_exponent - rhs_exponent; |
| const int overflow = number_of_lhs_digits + lhs_shift_amount - kPrecision; |
| if (overflow <= 0) { |
| lhs_coefficient = ScaleUp(lhs_coefficient, lhs_shift_amount); |
| } else { |
| lhs_coefficient = ScaleUp(lhs_coefficient, lhs_shift_amount - overflow); |
| rhs_coefficient = ScaleDown(rhs_coefficient, overflow); |
| exponent += overflow; |
| } |
| } |
| |
| } else if (lhs_exponent < rhs_exponent) { |
| const int number_of_rhs_digits = CountDigits(rhs_coefficient); |
| if (number_of_rhs_digits) { |
| const int rhs_shift_amount = rhs_exponent - lhs_exponent; |
| const int overflow = number_of_rhs_digits + rhs_shift_amount - kPrecision; |
| if (overflow <= 0) { |
| rhs_coefficient = ScaleUp(rhs_coefficient, rhs_shift_amount); |
| } else { |
| rhs_coefficient = ScaleUp(rhs_coefficient, rhs_shift_amount - overflow); |
| lhs_coefficient = ScaleDown(lhs_coefficient, overflow); |
| exponent += overflow; |
| } |
| } |
| } |
| |
| AlignedOperands aligned_operands; |
| aligned_operands.exponent = exponent; |
| aligned_operands.lhs_coefficient = lhs_coefficient; |
| aligned_operands.rhs_coefficient = rhs_coefficient; |
| return aligned_operands; |
| } |
| |
| 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 = data_.Coefficient(); |
| const int number_of_digits = CountDigits(result); |
| const int number_of_drop_digits = -Exponent(); |
| if (number_of_digits <= number_of_drop_digits) |
| return IsPositive() ? Decimal(1) : Zero(kPositive); |
| |
| result = ScaleDown(result, number_of_drop_digits); |
| if (IsPositive() && |
| !IsMultiplePowersOfTen(data_.Coefficient(), number_of_drop_digits)) |
| ++result; |
| return Decimal(GetSign(), 0, result); |
| } |
| |
| Decimal Decimal::CompareTo(const Decimal& rhs) const { |
| const Decimal result(*this - rhs); |
| switch (result.data_.GetFormatClass()) { |
| case EncodedData::kClassInfinity: |
| return result.IsNegative() ? Decimal(-1) : Decimal(1); |
| |
| case EncodedData::kClassNaN: |
| case EncodedData::kClassNormal: |
| return result; |
| |
| case EncodedData::kClassZero: |
| return Zero(kPositive); |
| |
| default: |
| NOTREACHED(); |
| return Nan(); |
| } |
| } |
| |
| // Round toward negative infinity. |
| Decimal Decimal::Floor() const { |
| if (IsSpecial()) |
| return *this; |
| |
| if (Exponent() >= 0) |
| return *this; |
| |
| uint64_t result = data_.Coefficient(); |
| const int number_of_digits = CountDigits(result); |
| const int number_of_drop_digits = -Exponent(); |
| if (number_of_digits < number_of_drop_digits) |
| return IsPositive() ? Zero(kPositive) : Decimal(-1); |
| |
| result = ScaleDown(result, number_of_drop_digits); |
| if (IsNegative() && |
| !IsMultiplePowersOfTen(data_.Coefficient(), number_of_drop_digits)) |
| ++result; |
| return Decimal(GetSign(), 0, result); |
| } |
| |
| Decimal Decimal::FromDouble(double double_value) { |
| if (std::isfinite(double_value)) |
| return FromString(String::NumberToStringECMAScript(double_value)); |
| |
| if (std::isinf(double_value)) |
| return Infinity(double_value < 0 ? kNegative : kPositive); |
| |
| return Nan(); |
| } |
| |
| Decimal Decimal::FromString(const String& str) { |
| int exponent = 0; |
| Sign exponent_sign = kPositive; |
| int number_of_digits = 0; |
| int number_of_digits_after_dot = 0; |
| int number_of_extra_digits = 0; |
| Sign sign = kPositive; |
| |
| enum { |
| kStateDigit, |
| kStateDot, |
| kStateDotDigit, |
| kStateE, |
| kStateEDigit, |
| kStateESign, |
| kStateSign, |
| kStateStart, |
| kStateZero, |
| } state = kStateStart; |
| |
| #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 kStateDigit: |
| if (ch >= '0' && ch <= '9') { |
| if (number_of_digits < kPrecision) { |
| ++number_of_digits; |
| accumulator *= 10; |
| accumulator += ch - '0'; |
| } else { |
| ++number_of_extra_digits; |
| } |
| break; |
| } |
| |
| HandleCharAndBreak('.', kStateDot); |
| HandleTwoCharsAndBreak('E', 'e', kStateE); |
| return Nan(); |
| |
| case kStateDot: |
| case kStateDotDigit: |
| if (ch >= '0' && ch <= '9') { |
| if (number_of_digits < kPrecision) { |
| ++number_of_digits; |
| ++number_of_digits_after_dot; |
| accumulator *= 10; |
| accumulator += ch - '0'; |
| } |
| state = kStateDotDigit; |
| break; |
| } |
| |
| HandleTwoCharsAndBreak('E', 'e', kStateE); |
| return Nan(); |
| |
| case kStateE: |
| if (ch == '+') { |
| exponent_sign = kPositive; |
| state = kStateESign; |
| break; |
| } |
| |
| if (ch == '-') { |
| exponent_sign = kNegative; |
| state = kStateESign; |
| break; |
| } |
| |
| if (ch >= '0' && ch <= '9') { |
| exponent = ch - '0'; |
| state = kStateEDigit; |
| break; |
| } |
| |
| return Nan(); |
| |
| case kStateEDigit: |
| if (ch >= '0' && ch <= '9') { |
| exponent *= 10; |
| exponent += ch - '0'; |
| if (exponent > kExponentMax + kPrecision) { |
| if (accumulator) |
| return exponent_sign == kNegative ? Zero(kPositive) |
| : Infinity(sign); |
| return Zero(sign); |
| } |
| state = kStateEDigit; |
| break; |
| } |
| |
| return Nan(); |
| |
| case kStateESign: |
| if (ch >= '0' && ch <= '9') { |
| exponent = ch - '0'; |
| state = kStateEDigit; |
| break; |
| } |
| |
| return Nan(); |
| |
| case kStateSign: |
| if (ch >= '1' && ch <= '9') { |
| accumulator = ch - '0'; |
| number_of_digits = 1; |
| state = kStateDigit; |
| break; |
| } |
| |
| HandleCharAndBreak('0', kStateZero); |
| HandleCharAndBreak('.', kStateDot); |
| return Nan(); |
| |
| case kStateStart: |
| if (ch >= '1' && ch <= '9') { |
| accumulator = ch - '0'; |
| number_of_digits = 1; |
| state = kStateDigit; |
| break; |
| } |
| |
| if (ch == '-') { |
| sign = kNegative; |
| state = kStateSign; |
| break; |
| } |
| |
| if (ch == '+') { |
| sign = kPositive; |
| state = kStateSign; |
| break; |
| } |
| |
| HandleCharAndBreak('0', kStateZero); |
| HandleCharAndBreak('.', kStateDot); |
| return Nan(); |
| |
| case kStateZero: |
| if (ch == '0') |
| break; |
| |
| if (ch >= '1' && ch <= '9') { |
| accumulator = ch - '0'; |
| number_of_digits = 1; |
| state = kStateDigit; |
| break; |
| } |
| |
| HandleCharAndBreak('.', kStateDot); |
| HandleTwoCharsAndBreak('E', 'e', kStateE); |
| return Nan(); |
| |
| default: |
| NOTREACHED(); |
| return Nan(); |
| } |
| } |
| |
| if (state == kStateZero) |
| return Zero(sign); |
| |
| if (state == kStateDigit || state == kStateEDigit || |
| state == kStateDotDigit) { |
| int result_exponent = exponent * (exponent_sign == kNegative ? -1 : 1) - |
| number_of_digits_after_dot + number_of_extra_digits; |
| if (result_exponent < kExponentMin) |
| return Zero(kPositive); |
| |
| const int overflow = result_exponent - kExponentMax + 1; |
| if (overflow > 0) { |
| if (overflow + number_of_digits - number_of_digits_after_dot > kPrecision) |
| return Infinity(sign); |
| accumulator = ScaleUp(accumulator, overflow); |
| result_exponent -= overflow; |
| } |
| |
| return Decimal(sign, result_exponent, accumulator); |
| } |
| |
| return Nan(); |
| } |
| |
| Decimal Decimal::Infinity(const Sign sign) { |
| return Decimal(EncodedData(sign, EncodedData::kClassInfinity)); |
| } |
| |
| Decimal Decimal::Nan() { |
| return Decimal(EncodedData(kPositive, EncodedData::kClassNaN)); |
| } |
| |
| 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 = data_.Coefficient(); |
| const int number_of_digits = CountDigits(result); |
| const int number_of_drop_digits = -Exponent(); |
| if (number_of_digits < number_of_drop_digits) |
| return Zero(kPositive); |
| |
| result = ScaleDown(result, number_of_drop_digits - 1); |
| if (result % 10 >= 5) |
| result += 10; |
| result /= 10; |
| return Decimal(GetSign(), 0, result); |
| } |
| |
| double Decimal::ToDouble() const { |
| if (IsFinite()) { |
| bool valid; |
| const double double_value = ToString().ToDouble(&valid); |
| return valid ? double_value : 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 (data_.GetFormatClass()) { |
| case EncodedData::kClassInfinity: |
| return GetSign() ? "-Infinity" : "Infinity"; |
| |
| case EncodedData::kClassNaN: |
| return "NaN"; |
| |
| case EncodedData::kClassNormal: |
| case EncodedData::kClassZero: |
| break; |
| |
| default: |
| NOTREACHED(); |
| return ""; |
| } |
| |
| StringBuilder builder; |
| if (GetSign()) |
| builder.Append('-'); |
| |
| int original_exponent = Exponent(); |
| uint64_t coefficient = data_.Coefficient(); |
| |
| if (original_exponent < 0) { |
| const int kMaxDigits = DBL_DIG; |
| uint64_t last_digit = 0; |
| while (CountDigits(coefficient) > kMaxDigits) { |
| last_digit = coefficient % 10; |
| coefficient /= 10; |
| ++original_exponent; |
| } |
| |
| if (last_digit >= 5) |
| ++coefficient; |
| |
| while (original_exponent < 0 && coefficient && !(coefficient % 10)) { |
| coefficient /= 10; |
| ++original_exponent; |
| } |
| } |
| |
| const String digits = String::Number(coefficient); |
| int coefficient_length = static_cast<int>(digits.length()); |
| const int adjusted_exponent = original_exponent + coefficient_length - 1; |
| if (original_exponent <= 0 && adjusted_exponent >= -6) { |
| if (!original_exponent) { |
| builder.Append(digits); |
| return builder.ToString(); |
| } |
| |
| if (adjusted_exponent >= 0) { |
| for (int i = 0; i < coefficient_length; ++i) { |
| builder.Append(digits[i]); |
| if (i == adjusted_exponent) |
| builder.Append('.'); |
| } |
| return builder.ToString(); |
| } |
| |
| builder.Append("0."); |
| for (int i = adjusted_exponent + 1; i < 0; ++i) |
| builder.Append('0'); |
| |
| builder.Append(digits); |
| |
| } else { |
| builder.Append(digits[0]); |
| while (coefficient_length >= 2 && digits[coefficient_length - 1] == '0') |
| --coefficient_length; |
| if (coefficient_length >= 2) { |
| builder.Append('.'); |
| for (int i = 1; i < coefficient_length; ++i) |
| builder.Append(digits[i]); |
| } |
| |
| if (adjusted_exponent) { |
| builder.Append(adjusted_exponent < 0 ? "e" : "e+"); |
| builder.AppendNumber(adjusted_exponent); |
| } |
| } |
| return builder.ToString(); |
| } |
| |
| Decimal Decimal::Zero(Sign sign) { |
| return Decimal(EncodedData(sign, EncodedData::kClassZero)); |
| } |
| |
| std::ostream& operator<<(std::ostream& ostream, const Decimal& decimal) { |
| Decimal::EncodedData data = decimal.Value(); |
| return ostream << "encode(" << String::Number(data.Coefficient()).Ascii() |
| << ", " << String::Number(data.Exponent()).Ascii() << ", " |
| << (data.GetSign() == Decimal::kNegative ? "Negative" |
| : "Positive") |
| << ")=" << decimal.ToString().Ascii(); |
| } |
| |
| } // namespace blink |