mfbt/decimal/Decimal.cpp

changeset 0
6474c204b198
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/mfbt/decimal/Decimal.cpp	Wed Dec 31 06:09:35 2014 +0100
     1.3 @@ -0,0 +1,1056 @@
     1.4 +/*
     1.5 + * Copyright (C) 2012 Google Inc. All rights reserved.
     1.6 + *
     1.7 + * Redistribution and use in source and binary forms, with or without
     1.8 + * modification, are permitted provided that the following conditions are
     1.9 + * met:
    1.10 + *
    1.11 + *     * Redistributions of source code must retain the above copyright
    1.12 + * notice, this list of conditions and the following disclaimer.
    1.13 + *     * Redistributions in binary form must reproduce the above
    1.14 + * copyright notice, this list of conditions and the following disclaimer
    1.15 + * in the documentation and/or other materials provided with the
    1.16 + * distribution.
    1.17 + *     * Neither the name of Google Inc. nor the names of its
    1.18 + * contributors may be used to endorse or promote products derived from
    1.19 + * this software without specific prior written permission.
    1.20 + *
    1.21 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    1.22 + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    1.23 + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    1.24 + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    1.25 + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    1.26 + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    1.27 + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    1.28 + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    1.29 + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    1.30 + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    1.31 + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
    1.32 + */
    1.33 +
    1.34 +#include "Decimal.h"
    1.35 +#include "moz-decimal-utils.h"
    1.36 +
    1.37 +#include <algorithm>
    1.38 +#include <float.h>
    1.39 +
    1.40 +using namespace moz_decimal_utils;
    1.41 +
    1.42 +namespace WebCore {
    1.43 +
    1.44 +namespace DecimalPrivate {
    1.45 +
    1.46 +static int const ExponentMax = 1023;
    1.47 +static int const ExponentMin = -1023;
    1.48 +static int const Precision = 18;
    1.49 +
    1.50 +static const uint64_t MaxCoefficient = UINT64_C(0x16345785D89FFFF); // 999999999999999999 == 18 9's
    1.51 +
    1.52 +// This class handles Decimal special values.
    1.53 +class SpecialValueHandler {
    1.54 +    WTF_MAKE_NONCOPYABLE(SpecialValueHandler);
    1.55 +public:
    1.56 +    enum HandleResult {
    1.57 +        BothFinite,
    1.58 +        BothInfinity,
    1.59 +        EitherNaN,
    1.60 +        LHSIsInfinity,
    1.61 +        RHSIsInfinity,
    1.62 +    };
    1.63 +
    1.64 +    SpecialValueHandler(const Decimal& lhs, const Decimal& rhs);
    1.65 +    HandleResult handle();
    1.66 +    Decimal value() const;
    1.67 +
    1.68 +private:
    1.69 +    enum Result {
    1.70 +        ResultIsLHS,
    1.71 +        ResultIsRHS,
    1.72 +        ResultIsUnknown,
    1.73 +    };
    1.74 +
    1.75 +    const Decimal& m_lhs;
    1.76 +    const Decimal& m_rhs;
    1.77 +    Result m_result;
    1.78 +};
    1.79 +
    1.80 +SpecialValueHandler::SpecialValueHandler(const Decimal& lhs, const Decimal& rhs)
    1.81 +    : m_lhs(lhs), m_rhs(rhs), m_result(ResultIsUnknown)
    1.82 +{
    1.83 +}
    1.84 +
    1.85 +SpecialValueHandler::HandleResult SpecialValueHandler::handle()
    1.86 +{
    1.87 +    if (m_lhs.isFinite() && m_rhs.isFinite())
    1.88 +        return BothFinite;
    1.89 +
    1.90 +    const Decimal::EncodedData::FormatClass lhsClass = m_lhs.value().formatClass();
    1.91 +    const Decimal::EncodedData::FormatClass rhsClass = m_rhs.value().formatClass();
    1.92 +    if (lhsClass == Decimal::EncodedData::ClassNaN) {
    1.93 +        m_result = ResultIsLHS;
    1.94 +        return EitherNaN;
    1.95 +     }
    1.96 +
    1.97 +    if (rhsClass == Decimal::EncodedData::ClassNaN) {
    1.98 +        m_result = ResultIsRHS;
    1.99 +        return EitherNaN;
   1.100 +     }
   1.101 +
   1.102 +    if (lhsClass == Decimal::EncodedData::ClassInfinity)
   1.103 +        return rhsClass == Decimal::EncodedData::ClassInfinity ? BothInfinity : LHSIsInfinity;
   1.104 +
   1.105 +    if (rhsClass == Decimal::EncodedData::ClassInfinity)
   1.106 +        return RHSIsInfinity;
   1.107 +
   1.108 +    ASSERT_NOT_REACHED();
   1.109 +    return BothFinite;
   1.110 +}
   1.111 +
   1.112 +Decimal SpecialValueHandler::value() const
   1.113 +{
   1.114 +    switch (m_result) {
   1.115 +    case ResultIsLHS:
   1.116 +        return m_lhs;
   1.117 +    case ResultIsRHS:
   1.118 +        return m_rhs;
   1.119 +    case ResultIsUnknown:
   1.120 +    default:
   1.121 +        ASSERT_NOT_REACHED();
   1.122 +        return m_lhs;
   1.123 +    }
   1.124 +}
   1.125 +
   1.126 +// This class is used for 128 bit unsigned integer arithmetic.
   1.127 +class UInt128 {
   1.128 +public:
   1.129 +    UInt128(uint64_t low, uint64_t high)
   1.130 +        : m_high(high), m_low(low)
   1.131 +    {
   1.132 +    }
   1.133 +
   1.134 +    UInt128& operator/=(uint32_t);
   1.135 +
   1.136 +    uint64_t high() const { return m_high; }
   1.137 +    uint64_t low() const { return m_low; }
   1.138 +
   1.139 +    static UInt128 multiply(uint64_t u, uint64_t v) { return UInt128(u * v, multiplyHigh(u, v)); }
   1.140 +
   1.141 +private:
   1.142 +    static uint32_t highUInt32(uint64_t x) { return static_cast<uint32_t>(x >> 32); }
   1.143 +    static uint32_t lowUInt32(uint64_t x) { return static_cast<uint32_t>(x & ((static_cast<uint64_t>(1) << 32) - 1)); }
   1.144 +    bool isZero() const { return !m_low && !m_high; }
   1.145 +    static uint64_t makeUInt64(uint32_t low, uint32_t high) { return low | (static_cast<uint64_t>(high) << 32); }
   1.146 +
   1.147 +    static uint64_t multiplyHigh(uint64_t, uint64_t);
   1.148 +
   1.149 +    uint64_t m_high;
   1.150 +    uint64_t m_low;
   1.151 +};
   1.152 +
   1.153 +UInt128& UInt128::operator/=(const uint32_t divisor)
   1.154 +{
   1.155 +    ASSERT(divisor);
   1.156 +
   1.157 +    if (!m_high) {
   1.158 +        m_low /= divisor;
   1.159 +        return *this;
   1.160 +    }
   1.161 +
   1.162 +    uint32_t dividend[4];
   1.163 +    dividend[0] = lowUInt32(m_low);
   1.164 +    dividend[1] = highUInt32(m_low);
   1.165 +    dividend[2] = lowUInt32(m_high);
   1.166 +    dividend[3] = highUInt32(m_high);
   1.167 +
   1.168 +    uint32_t quotient[4];
   1.169 +    uint32_t remainder = 0;
   1.170 +    for (int i = 3; i >= 0; --i) {
   1.171 +        const uint64_t work = makeUInt64(dividend[i], remainder);
   1.172 +        remainder = static_cast<uint32_t>(work % divisor);
   1.173 +        quotient[i] = static_cast<uint32_t>(work / divisor);
   1.174 +    }
   1.175 +    m_low = makeUInt64(quotient[0], quotient[1]);
   1.176 +    m_high = makeUInt64(quotient[2], quotient[3]);
   1.177 +    return *this;
   1.178 +}
   1.179 +
   1.180 +// Returns high 64bit of 128bit product.
   1.181 +uint64_t UInt128::multiplyHigh(uint64_t u, uint64_t v)
   1.182 +{
   1.183 +    const uint64_t uLow = lowUInt32(u);
   1.184 +    const uint64_t uHigh = highUInt32(u);
   1.185 +    const uint64_t vLow = lowUInt32(v);
   1.186 +    const uint64_t vHigh = highUInt32(v);
   1.187 +    const uint64_t partialProduct = uHigh * vLow + highUInt32(uLow * vLow);
   1.188 +    return uHigh * vHigh + highUInt32(partialProduct) + highUInt32(uLow * vHigh + lowUInt32(partialProduct));
   1.189 +}
   1.190 +
   1.191 +static int countDigits(uint64_t x)
   1.192 +{
   1.193 +    int numberOfDigits = 0;
   1.194 +    for (uint64_t powerOfTen = 1; x >= powerOfTen; powerOfTen *= 10) {
   1.195 +        ++numberOfDigits;
   1.196 +        if (powerOfTen >= std::numeric_limits<uint64_t>::max() / 10)
   1.197 +            break;
   1.198 +    }
   1.199 +    return numberOfDigits;
   1.200 +}
   1.201 +
   1.202 +static uint64_t scaleDown(uint64_t x, int n)
   1.203 +{
   1.204 +    ASSERT(n >= 0);
   1.205 +    while (n > 0 && x) {
   1.206 +        x /= 10;
   1.207 +        --n;
   1.208 +    }
   1.209 +    return x;
   1.210 +}
   1.211 +
   1.212 +static uint64_t scaleUp(uint64_t x, int n)
   1.213 +{
   1.214 +    ASSERT(n >= 0);
   1.215 +    ASSERT(n < Precision);
   1.216 +
   1.217 +    uint64_t y = 1;
   1.218 +    uint64_t z = 10;
   1.219 +    for (;;) {
   1.220 +        if (n & 1)
   1.221 +            y = y * z;
   1.222 +
   1.223 +        n >>= 1;
   1.224 +        if (!n)
   1.225 +            return x * y;
   1.226 +
   1.227 +        z = z * z;
   1.228 +    }
   1.229 +}
   1.230 +
   1.231 +} // namespace DecimalPrivate
   1.232 +
   1.233 +using namespace DecimalPrivate;
   1.234 +
   1.235 +Decimal::EncodedData::EncodedData(Sign sign, FormatClass formatClass)
   1.236 +    : m_coefficient(0)
   1.237 +    , m_exponent(0)
   1.238 +    , m_formatClass(formatClass)
   1.239 +    , m_sign(sign)
   1.240 +{
   1.241 +}
   1.242 +
   1.243 +Decimal::EncodedData::EncodedData(Sign sign, int exponent, uint64_t coefficient)
   1.244 +    : m_formatClass(coefficient ? ClassNormal : ClassZero)
   1.245 +    , m_sign(sign)
   1.246 +{
   1.247 +    if (exponent >= ExponentMin && exponent <= ExponentMax) {
   1.248 +        while (coefficient > MaxCoefficient) {
   1.249 +            coefficient /= 10;
   1.250 +            ++exponent;
   1.251 +        }
   1.252 +    }
   1.253 +
   1.254 +    if (exponent > ExponentMax) {
   1.255 +        m_coefficient = 0;
   1.256 +        m_exponent = 0;
   1.257 +        m_formatClass = ClassInfinity;
   1.258 +        return;
   1.259 +    }
   1.260 +
   1.261 +    if (exponent < ExponentMin) {
   1.262 +        m_coefficient = 0;
   1.263 +        m_exponent = 0;
   1.264 +        m_formatClass = ClassZero;
   1.265 +        return;
   1.266 +    }
   1.267 +
   1.268 +    m_coefficient = coefficient;
   1.269 +    m_exponent = static_cast<int16_t>(exponent);
   1.270 +}
   1.271 +
   1.272 +bool Decimal::EncodedData::operator==(const EncodedData& another) const
   1.273 +{
   1.274 +    return m_sign == another.m_sign
   1.275 +        && m_formatClass == another.m_formatClass
   1.276 +        && m_exponent == another.m_exponent
   1.277 +        && m_coefficient == another.m_coefficient;
   1.278 +}
   1.279 +
   1.280 +Decimal::Decimal(int32_t i32)
   1.281 +    : m_data(i32 < 0 ? Negative : Positive, 0, i32 < 0 ? static_cast<uint64_t>(-static_cast<int64_t>(i32)) : static_cast<uint64_t>(i32))
   1.282 +{
   1.283 +}
   1.284 +
   1.285 +Decimal::Decimal(Sign sign, int exponent, uint64_t coefficient)
   1.286 +    : m_data(sign, coefficient ? exponent : 0, coefficient)
   1.287 +{
   1.288 +}
   1.289 +
   1.290 +Decimal::Decimal(const EncodedData& data)
   1.291 +    : m_data(data)
   1.292 +{
   1.293 +}
   1.294 +
   1.295 +Decimal::Decimal(const Decimal& other)
   1.296 +    : m_data(other.m_data)
   1.297 +{
   1.298 +}
   1.299 +
   1.300 +Decimal& Decimal::operator=(const Decimal& other)
   1.301 +{
   1.302 +    m_data = other.m_data;
   1.303 +    return *this;
   1.304 +}
   1.305 +
   1.306 +Decimal& Decimal::operator+=(const Decimal& other)
   1.307 +{
   1.308 +    m_data = (*this + other).m_data;
   1.309 +    return *this;
   1.310 +}
   1.311 +
   1.312 +Decimal& Decimal::operator-=(const Decimal& other)
   1.313 +{
   1.314 +    m_data = (*this - other).m_data;
   1.315 +    return *this;
   1.316 +}
   1.317 +
   1.318 +Decimal& Decimal::operator*=(const Decimal& other)
   1.319 +{
   1.320 +    m_data = (*this * other).m_data;
   1.321 +    return *this;
   1.322 +}
   1.323 +
   1.324 +Decimal& Decimal::operator/=(const Decimal& other)
   1.325 +{
   1.326 +    m_data = (*this / other).m_data;
   1.327 +    return *this;
   1.328 +}
   1.329 +
   1.330 +Decimal Decimal::operator-() const
   1.331 +{
   1.332 +    if (isNaN())
   1.333 +        return *this;
   1.334 +
   1.335 +    Decimal result(*this);
   1.336 +    result.m_data.setSign(invertSign(m_data.sign()));
   1.337 +    return result;
   1.338 +}
   1.339 +
   1.340 +Decimal Decimal::operator+(const Decimal& rhs) const
   1.341 +{
   1.342 +    const Decimal& lhs = *this;
   1.343 +    const Sign lhsSign = lhs.sign();
   1.344 +    const Sign rhsSign = rhs.sign();
   1.345 +
   1.346 +    SpecialValueHandler handler(lhs, rhs);
   1.347 +    switch (handler.handle()) {
   1.348 +    case SpecialValueHandler::BothFinite:
   1.349 +        break;
   1.350 +
   1.351 +    case SpecialValueHandler::BothInfinity:
   1.352 +        return lhsSign == rhsSign ? lhs : nan();
   1.353 +
   1.354 +    case SpecialValueHandler::EitherNaN:
   1.355 +        return handler.value();
   1.356 +
   1.357 +    case SpecialValueHandler::LHSIsInfinity:
   1.358 +        return lhs;
   1.359 +
   1.360 +    case SpecialValueHandler::RHSIsInfinity:
   1.361 +        return rhs;
   1.362 +    }
   1.363 +
   1.364 +    const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
   1.365 +
   1.366 +    const uint64_t result = lhsSign == rhsSign
   1.367 +        ? alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient
   1.368 +        : alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient;
   1.369 +
   1.370 +    if (lhsSign == Negative && rhsSign == Positive && !result)
   1.371 +        return Decimal(Positive, alignedOperands.exponent, 0);
   1.372 +
   1.373 +    return static_cast<int64_t>(result) >= 0
   1.374 +        ? Decimal(lhsSign, alignedOperands.exponent, result)
   1.375 +        : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
   1.376 +}
   1.377 +
   1.378 +Decimal Decimal::operator-(const Decimal& rhs) const
   1.379 +{
   1.380 +    const Decimal& lhs = *this;
   1.381 +    const Sign lhsSign = lhs.sign();
   1.382 +    const Sign rhsSign = rhs.sign();
   1.383 +
   1.384 +    SpecialValueHandler handler(lhs, rhs);
   1.385 +    switch (handler.handle()) {
   1.386 +    case SpecialValueHandler::BothFinite:
   1.387 +        break;
   1.388 +
   1.389 +    case SpecialValueHandler::BothInfinity:
   1.390 +        return lhsSign == rhsSign ? nan() : lhs;
   1.391 +
   1.392 +    case SpecialValueHandler::EitherNaN:
   1.393 +        return handler.value();
   1.394 +
   1.395 +    case SpecialValueHandler::LHSIsInfinity:
   1.396 +        return lhs;
   1.397 +
   1.398 +    case SpecialValueHandler::RHSIsInfinity:
   1.399 +        return infinity(invertSign(rhsSign));
   1.400 +    }
   1.401 +
   1.402 +    const AlignedOperands alignedOperands = alignOperands(lhs, rhs);
   1.403 +
   1.404 +    const uint64_t result = lhsSign == rhsSign
   1.405 +        ? alignedOperands.lhsCoefficient - alignedOperands.rhsCoefficient
   1.406 +        : alignedOperands.lhsCoefficient + alignedOperands.rhsCoefficient;
   1.407 +
   1.408 +    if (lhsSign == Negative && rhsSign == Negative && !result)
   1.409 +        return Decimal(Positive, alignedOperands.exponent, 0);
   1.410 +
   1.411 +    return static_cast<int64_t>(result) >= 0
   1.412 +        ? Decimal(lhsSign, alignedOperands.exponent, result)
   1.413 +        : Decimal(invertSign(lhsSign), alignedOperands.exponent, -static_cast<int64_t>(result));
   1.414 +}
   1.415 +
   1.416 +Decimal Decimal::operator*(const Decimal& rhs) const
   1.417 +{
   1.418 +    const Decimal& lhs = *this;
   1.419 +    const Sign lhsSign = lhs.sign();
   1.420 +    const Sign rhsSign = rhs.sign();
   1.421 +    const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
   1.422 +
   1.423 +    SpecialValueHandler handler(lhs, rhs);
   1.424 +    switch (handler.handle()) {
   1.425 +    case SpecialValueHandler::BothFinite: {
   1.426 +        const uint64_t lhsCoefficient = lhs.m_data.coefficient();
   1.427 +        const uint64_t rhsCoefficient = rhs.m_data.coefficient();
   1.428 +        int resultExponent = lhs.exponent() + rhs.exponent();
   1.429 +        UInt128 work(UInt128::multiply(lhsCoefficient, rhsCoefficient));
   1.430 +        while (work.high()) {
   1.431 +            work /= 10;
   1.432 +            ++resultExponent;
   1.433 +        }
   1.434 +        return Decimal(resultSign, resultExponent, work.low());
   1.435 +    }
   1.436 +
   1.437 +    case SpecialValueHandler::BothInfinity:
   1.438 +        return infinity(resultSign);
   1.439 +
   1.440 +    case SpecialValueHandler::EitherNaN:
   1.441 +        return handler.value();
   1.442 +
   1.443 +    case SpecialValueHandler::LHSIsInfinity:
   1.444 +        return rhs.isZero() ? nan() : infinity(resultSign);
   1.445 +
   1.446 +    case SpecialValueHandler::RHSIsInfinity:
   1.447 +        return lhs.isZero() ? nan() : infinity(resultSign);
   1.448 +    }
   1.449 +
   1.450 +    ASSERT_NOT_REACHED();
   1.451 +    return nan();
   1.452 +}
   1.453 +
   1.454 +Decimal Decimal::operator/(const Decimal& rhs) const
   1.455 +{
   1.456 +    const Decimal& lhs = *this;
   1.457 +    const Sign lhsSign = lhs.sign();
   1.458 +    const Sign rhsSign = rhs.sign();
   1.459 +    const Sign resultSign = lhsSign == rhsSign ? Positive : Negative;
   1.460 +
   1.461 +    SpecialValueHandler handler(lhs, rhs);
   1.462 +    switch (handler.handle()) {
   1.463 +    case SpecialValueHandler::BothFinite:
   1.464 +        break;
   1.465 +
   1.466 +    case SpecialValueHandler::BothInfinity:
   1.467 +        return nan();
   1.468 +
   1.469 +    case SpecialValueHandler::EitherNaN:
   1.470 +        return handler.value();
   1.471 +
   1.472 +    case SpecialValueHandler::LHSIsInfinity:
   1.473 +        return infinity(resultSign);
   1.474 +
   1.475 +    case SpecialValueHandler::RHSIsInfinity:
   1.476 +        return zero(resultSign);
   1.477 +    }
   1.478 +
   1.479 +    ASSERT(lhs.isFinite());
   1.480 +    ASSERT(rhs.isFinite());
   1.481 +
   1.482 +    if (rhs.isZero())
   1.483 +        return lhs.isZero() ? nan() : infinity(resultSign);
   1.484 +
   1.485 +    int resultExponent = lhs.exponent() - rhs.exponent();
   1.486 +
   1.487 +    if (lhs.isZero())
   1.488 +        return Decimal(resultSign, resultExponent, 0);
   1.489 +
   1.490 +    uint64_t remainder = lhs.m_data.coefficient();
   1.491 +    const uint64_t divisor = rhs.m_data.coefficient();
   1.492 +    uint64_t result = 0;
   1.493 +    while (result < MaxCoefficient / 100) {
   1.494 +        while (remainder < divisor) {
   1.495 +            remainder *= 10;
   1.496 +            result *= 10;
   1.497 +            --resultExponent;
   1.498 +        }
   1.499 +        result += remainder / divisor;
   1.500 +        remainder %= divisor;
   1.501 +        if (!remainder)
   1.502 +            break;
   1.503 +    }
   1.504 +
   1.505 +    if (remainder > divisor / 2)
   1.506 +        ++result;
   1.507 +
   1.508 +    return Decimal(resultSign, resultExponent, result);
   1.509 +}
   1.510 +
   1.511 +bool Decimal::operator==(const Decimal& rhs) const
   1.512 +{
   1.513 +    if (isNaN() || rhs.isNaN())
   1.514 +        return false;
   1.515 +    return m_data == rhs.m_data || compareTo(rhs).isZero();
   1.516 +}
   1.517 +
   1.518 +bool Decimal::operator!=(const Decimal& rhs) const
   1.519 +{
   1.520 +    if (isNaN() || rhs.isNaN())
   1.521 +        return true;
   1.522 +    if (m_data == rhs.m_data)
   1.523 +        return false;
   1.524 +    const Decimal result = compareTo(rhs);
   1.525 +    if (result.isNaN())
   1.526 +        return false;
   1.527 +    return !result.isZero();
   1.528 +}
   1.529 +
   1.530 +bool Decimal::operator<(const Decimal& rhs) const
   1.531 +{
   1.532 +    const Decimal result = compareTo(rhs);
   1.533 +    if (result.isNaN())
   1.534 +        return false;
   1.535 +    return !result.isZero() && result.isNegative();
   1.536 +}
   1.537 +
   1.538 +bool Decimal::operator<=(const Decimal& rhs) const
   1.539 +{
   1.540 +    if (isNaN() || rhs.isNaN())
   1.541 +        return false;
   1.542 +    if (m_data == rhs.m_data)
   1.543 +        return true;
   1.544 +    const Decimal result = compareTo(rhs);
   1.545 +    if (result.isNaN())
   1.546 +        return false;
   1.547 +    return result.isZero() || result.isNegative();
   1.548 +}
   1.549 +
   1.550 +bool Decimal::operator>(const Decimal& rhs) const
   1.551 +{
   1.552 +    const Decimal result = compareTo(rhs);
   1.553 +    if (result.isNaN())
   1.554 +        return false;
   1.555 +    return !result.isZero() && result.isPositive();
   1.556 +}
   1.557 +
   1.558 +bool Decimal::operator>=(const Decimal& rhs) const
   1.559 +{
   1.560 +    if (isNaN() || rhs.isNaN())
   1.561 +        return false;
   1.562 +    if (m_data == rhs.m_data)
   1.563 +        return true;
   1.564 +    const Decimal result = compareTo(rhs);
   1.565 +    if (result.isNaN())
   1.566 +        return false;
   1.567 +    return result.isZero() || !result.isNegative();
   1.568 +}
   1.569 +
   1.570 +Decimal Decimal::abs() const
   1.571 +{
   1.572 +    Decimal result(*this);
   1.573 +    result.m_data.setSign(Positive);
   1.574 +    return result;
   1.575 +}
   1.576 +
   1.577 +Decimal::AlignedOperands Decimal::alignOperands(const Decimal& lhs, const Decimal& rhs)
   1.578 +{
   1.579 +    ASSERT(lhs.isFinite());
   1.580 +    ASSERT(rhs.isFinite());
   1.581 +
   1.582 +    const int lhsExponent = lhs.exponent();
   1.583 +    const int rhsExponent = rhs.exponent();
   1.584 +    int exponent = std::min(lhsExponent, rhsExponent);
   1.585 +    uint64_t lhsCoefficient = lhs.m_data.coefficient();
   1.586 +    uint64_t rhsCoefficient = rhs.m_data.coefficient();
   1.587 +
   1.588 +    if (lhsExponent > rhsExponent) {
   1.589 +        const int numberOfLHSDigits = countDigits(lhsCoefficient);
   1.590 +        if (numberOfLHSDigits) {
   1.591 +            const int lhsShiftAmount = lhsExponent - rhsExponent;
   1.592 +            const int overflow = numberOfLHSDigits + lhsShiftAmount - Precision;
   1.593 +            if (overflow <= 0)
   1.594 +                lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount);
   1.595 +            else {
   1.596 +                lhsCoefficient = scaleUp(lhsCoefficient, lhsShiftAmount - overflow);
   1.597 +                rhsCoefficient = scaleDown(rhsCoefficient, overflow);
   1.598 +                exponent += overflow;
   1.599 +            }
   1.600 +        }
   1.601 +
   1.602 +    } else if (lhsExponent < rhsExponent) {
   1.603 +        const int numberOfRHSDigits = countDigits(rhsCoefficient);
   1.604 +        if (numberOfRHSDigits) {
   1.605 +            const int rhsShiftAmount = rhsExponent - lhsExponent;
   1.606 +            const int overflow = numberOfRHSDigits + rhsShiftAmount - Precision;
   1.607 +            if (overflow <= 0)
   1.608 +                rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount);
   1.609 +            else {
   1.610 +                rhsCoefficient = scaleUp(rhsCoefficient, rhsShiftAmount - overflow);
   1.611 +                lhsCoefficient = scaleDown(lhsCoefficient, overflow);
   1.612 +                exponent += overflow;
   1.613 +            }
   1.614 +        }
   1.615 +    }
   1.616 +
   1.617 +    AlignedOperands alignedOperands;
   1.618 +    alignedOperands.exponent = exponent;
   1.619 +    alignedOperands.lhsCoefficient = lhsCoefficient;
   1.620 +    alignedOperands.rhsCoefficient = rhsCoefficient;
   1.621 +    return alignedOperands;
   1.622 +}
   1.623 +
   1.624 +// Round toward positive infinity.
   1.625 +// Note: Mac ports defines ceil(x) as wtf_ceil(x), so we can't use name "ceil" here.
   1.626 +Decimal Decimal::ceiling() const
   1.627 +{
   1.628 +    if (isSpecial())
   1.629 +        return *this;
   1.630 +
   1.631 +    if (exponent() >= 0)
   1.632 +        return *this;
   1.633 +
   1.634 +    uint64_t coefficient = m_data.coefficient();
   1.635 +    const int numberOfDigits = countDigits(coefficient);
   1.636 +    const int numberOfDropDigits = -exponent();
   1.637 +    if (numberOfDigits < numberOfDropDigits)
   1.638 +        return isPositive() ? Decimal(1) : zero(Positive);
   1.639 +
   1.640 +    uint64_t result = scaleDown(coefficient, numberOfDropDigits);
   1.641 +    uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits);
   1.642 +    if (droppedDigits && isPositive())
   1.643 +        result += 1;
   1.644 +    return Decimal(sign(), 0, result);
   1.645 +}
   1.646 +
   1.647 +Decimal Decimal::compareTo(const Decimal& rhs) const
   1.648 +{
   1.649 +    const Decimal result(*this - rhs);
   1.650 +    switch (result.m_data.formatClass()) {
   1.651 +    case EncodedData::ClassInfinity:
   1.652 +        return result.isNegative() ? Decimal(-1) : Decimal(1);
   1.653 +
   1.654 +    case EncodedData::ClassNaN:
   1.655 +    case EncodedData::ClassNormal:
   1.656 +        return result;
   1.657 +
   1.658 +    case EncodedData::ClassZero:
   1.659 +        return zero(Positive);
   1.660 +
   1.661 +    default:
   1.662 +        ASSERT_NOT_REACHED();
   1.663 +        return nan();
   1.664 +    }
   1.665 +}
   1.666 +
   1.667 +// Round toward negative infinity.
   1.668 +Decimal Decimal::floor() const
   1.669 +{
   1.670 +    if (isSpecial())
   1.671 +        return *this;
   1.672 +
   1.673 +    if (exponent() >= 0)
   1.674 +        return *this;
   1.675 +
   1.676 +    uint64_t coefficient = m_data.coefficient();
   1.677 +    const int numberOfDigits = countDigits(coefficient);
   1.678 +    const int numberOfDropDigits = -exponent();
   1.679 +    if (numberOfDigits < numberOfDropDigits)
   1.680 +        return isPositive() ? zero(Positive) : Decimal(-1);
   1.681 +
   1.682 +    uint64_t result = scaleDown(coefficient, numberOfDropDigits);
   1.683 +    uint64_t droppedDigits = coefficient - scaleUp(result, numberOfDropDigits);
   1.684 +    if (droppedDigits && isNegative()) {
   1.685 +        result += 1;
   1.686 +    }
   1.687 +    return Decimal(sign(), 0, result);
   1.688 +}
   1.689 +
   1.690 +Decimal Decimal::fromDouble(double doubleValue)
   1.691 +{
   1.692 +    if (std::isfinite(doubleValue))
   1.693 +        return fromString(mozToString(doubleValue));
   1.694 +
   1.695 +    if (std::isinf(doubleValue))
   1.696 +        return infinity(doubleValue < 0 ? Negative : Positive);
   1.697 +
   1.698 +    return nan();
   1.699 +}
   1.700 +
   1.701 +Decimal Decimal::fromString(const String& str)
   1.702 +{
   1.703 +    int exponent = 0;
   1.704 +    Sign exponentSign = Positive;
   1.705 +    int numberOfDigits = 0;
   1.706 +    int numberOfDigitsAfterDot = 0;
   1.707 +    int numberOfExtraDigits = 0;
   1.708 +    Sign sign = Positive;
   1.709 +
   1.710 +    enum {
   1.711 +        StateDigit,
   1.712 +        StateDot,
   1.713 +        StateDotDigit,
   1.714 +        StateE,
   1.715 +        StateEDigit,
   1.716 +        StateESign,
   1.717 +        StateSign,
   1.718 +        StateStart,
   1.719 +        StateZero,
   1.720 +    } state = StateStart;
   1.721 +
   1.722 +#define HandleCharAndBreak(expected, nextState) \
   1.723 +    if (ch == expected) { \
   1.724 +        state = nextState; \
   1.725 +        break; \
   1.726 +    }
   1.727 +
   1.728 +#define HandleTwoCharsAndBreak(expected1, expected2, nextState) \
   1.729 +    if (ch == expected1 || ch == expected2) { \
   1.730 +        state = nextState; \
   1.731 +        break; \
   1.732 +    }
   1.733 +
   1.734 +    uint64_t accumulator = 0;
   1.735 +    for (unsigned index = 0; index < str.length(); ++index) {
   1.736 +        const int ch = str[index];
   1.737 +        switch (state) {
   1.738 +        case StateDigit:
   1.739 +            if (ch >= '0' && ch <= '9') {
   1.740 +                if (numberOfDigits < Precision) {
   1.741 +                    ++numberOfDigits;
   1.742 +                    accumulator *= 10;
   1.743 +                    accumulator += ch - '0';
   1.744 +                } else
   1.745 +                    ++numberOfExtraDigits;
   1.746 +                break;
   1.747 +            }
   1.748 +
   1.749 +            HandleCharAndBreak('.', StateDot);
   1.750 +            HandleTwoCharsAndBreak('E', 'e', StateE);
   1.751 +            return nan();
   1.752 +
   1.753 +        case StateDot:
   1.754 +            if (ch >= '0' && ch <= '9') {
   1.755 +                if (numberOfDigits < Precision) {
   1.756 +                    ++numberOfDigits;
   1.757 +                    ++numberOfDigitsAfterDot;
   1.758 +                    accumulator *= 10;
   1.759 +                    accumulator += ch - '0';
   1.760 +                }
   1.761 +                state = StateDotDigit;
   1.762 +                break;
   1.763 +            }
   1.764 +
   1.765 +        case StateDotDigit:
   1.766 +            if (ch >= '0' && ch <= '9') {
   1.767 +                if (numberOfDigits < Precision) {
   1.768 +                    ++numberOfDigits;
   1.769 +                    ++numberOfDigitsAfterDot;
   1.770 +                    accumulator *= 10;
   1.771 +                    accumulator += ch - '0';
   1.772 +                }
   1.773 +                break;
   1.774 +            }
   1.775 +
   1.776 +            HandleTwoCharsAndBreak('E', 'e', StateE);
   1.777 +            return nan();
   1.778 +
   1.779 +        case StateE:
   1.780 +            if (ch == '+') {
   1.781 +                exponentSign = Positive;
   1.782 +                state = StateESign;
   1.783 +                break;
   1.784 +            }
   1.785 +
   1.786 +            if (ch == '-') {
   1.787 +                exponentSign = Negative;
   1.788 +                state = StateESign;
   1.789 +                break;
   1.790 +            }
   1.791 +
   1.792 +            if (ch >= '0' && ch <= '9') {
   1.793 +                exponent = ch - '0';
   1.794 +                state = StateEDigit;
   1.795 +                break;
   1.796 +            }
   1.797 +
   1.798 +            return nan();
   1.799 +
   1.800 +        case StateEDigit:
   1.801 +            if (ch >= '0' && ch <= '9') {
   1.802 +                exponent *= 10;
   1.803 +                exponent += ch - '0';
   1.804 +                if (exponent > ExponentMax + Precision) {
   1.805 +                    if (accumulator)
   1.806 +                        return exponentSign == Negative ? zero(Positive) : infinity(sign);
   1.807 +                    return zero(sign);
   1.808 +                }
   1.809 +                state = StateEDigit;
   1.810 +                break;
   1.811 +            }
   1.812 +
   1.813 +            return nan();
   1.814 +
   1.815 +        case StateESign:
   1.816 +            if (ch >= '0' && ch <= '9') {
   1.817 +                exponent = ch - '0';
   1.818 +                state = StateEDigit;
   1.819 +                break;
   1.820 +            }
   1.821 +
   1.822 +            return nan();
   1.823 +
   1.824 +        case StateSign:
   1.825 +            if (ch >= '1' && ch <= '9') {
   1.826 +                accumulator = ch - '0';
   1.827 +                numberOfDigits = 1;
   1.828 +                state = StateDigit;
   1.829 +                break;
   1.830 +            }
   1.831 +
   1.832 +            HandleCharAndBreak('0', StateZero);
   1.833 +            return nan();
   1.834 +
   1.835 +        case StateStart:
   1.836 +            if (ch >= '1' && ch <= '9') {
   1.837 +                accumulator = ch - '0';
   1.838 +                numberOfDigits = 1;
   1.839 +                state = StateDigit;
   1.840 +                break;
   1.841 +            }
   1.842 +
   1.843 +            if (ch == '-') {
   1.844 +                sign = Negative;
   1.845 +                state = StateSign;
   1.846 +                break;
   1.847 +            }
   1.848 +
   1.849 +            if (ch == '+') {
   1.850 +                sign = Positive;
   1.851 +                state = StateSign;
   1.852 +                break;
   1.853 +            }
   1.854 +
   1.855 +            HandleCharAndBreak('0', StateZero);
   1.856 +            HandleCharAndBreak('.', StateDot);
   1.857 +            return nan();
   1.858 +
   1.859 +        case StateZero:
   1.860 +            if (ch == '0')
   1.861 +                break;
   1.862 +
   1.863 +            if (ch >= '1' && ch <= '9') {
   1.864 +                accumulator = ch - '0';
   1.865 +                numberOfDigits = 1;
   1.866 +                state = StateDigit;
   1.867 +                break;
   1.868 +            }
   1.869 +
   1.870 +            HandleCharAndBreak('.', StateDot);
   1.871 +            HandleTwoCharsAndBreak('E', 'e', StateE);
   1.872 +            return nan();
   1.873 +
   1.874 +        default:
   1.875 +            ASSERT_NOT_REACHED();
   1.876 +            return nan();
   1.877 +        }
   1.878 +    }
   1.879 +
   1.880 +    if (state == StateZero)
   1.881 +        return zero(sign);
   1.882 +
   1.883 +    if (state == StateDigit || state == StateEDigit || state == StateDotDigit) {
   1.884 +        int resultExponent = exponent * (exponentSign == Negative ? -1 : 1) - numberOfDigitsAfterDot + numberOfExtraDigits;
   1.885 +        if (resultExponent < ExponentMin)
   1.886 +            return zero(Positive);
   1.887 +
   1.888 +        const int overflow = resultExponent - ExponentMax + 1;
   1.889 +        if (overflow > 0) {
   1.890 +            if (overflow + numberOfDigits - numberOfDigitsAfterDot > Precision)
   1.891 +                return infinity(sign);
   1.892 +            accumulator = scaleUp(accumulator, overflow);
   1.893 +            resultExponent -= overflow;
   1.894 +        }
   1.895 +
   1.896 +        return Decimal(sign, resultExponent, accumulator);
   1.897 +    }
   1.898 +
   1.899 +    return nan();
   1.900 +}
   1.901 +
   1.902 +Decimal Decimal::infinity(const Sign sign)
   1.903 +{
   1.904 +    return Decimal(EncodedData(sign, EncodedData::ClassInfinity));
   1.905 +}
   1.906 +
   1.907 +Decimal Decimal::nan()
   1.908 +{
   1.909 +    return Decimal(EncodedData(Positive, EncodedData::ClassNaN));
   1.910 +}
   1.911 +
   1.912 +Decimal Decimal::remainder(const Decimal& rhs) const
   1.913 +{
   1.914 +    const Decimal quotient = *this / rhs;
   1.915 +    return quotient.isSpecial() ? quotient : *this - (quotient.isNegative() ? quotient.ceiling() : quotient.floor()) * rhs;
   1.916 +}
   1.917 +
   1.918 +Decimal Decimal::round() const
   1.919 +{
   1.920 +    if (isSpecial())
   1.921 +        return *this;
   1.922 +
   1.923 +    if (exponent() >= 0)
   1.924 +        return *this;
   1.925 +
   1.926 +    uint64_t result = m_data.coefficient();
   1.927 +    const int numberOfDigits = countDigits(result);
   1.928 +    const int numberOfDropDigits = -exponent();
   1.929 +    if (numberOfDigits < numberOfDropDigits)
   1.930 +        return zero(Positive);
   1.931 +
   1.932 +    // We're implementing round-half-away-from-zero, so we only need the one
   1.933 +    // (the most significant) fractional digit:
   1.934 +    result = scaleDown(result, numberOfDropDigits - 1);
   1.935 +    if (result % 10 >= 5)
   1.936 +        result += 10;
   1.937 +    result /= 10;
   1.938 +    return Decimal(sign(), 0, result);
   1.939 +}
   1.940 +
   1.941 +double Decimal::toDouble() const
   1.942 +{
   1.943 +    if (isFinite()) {
   1.944 +        bool valid;
   1.945 +        const double doubleValue = mozToDouble(toString(), &valid);
   1.946 +        return valid ? doubleValue : std::numeric_limits<double>::quiet_NaN();
   1.947 +    }
   1.948 +
   1.949 +    if (isInfinity())
   1.950 +        return isNegative() ? -std::numeric_limits<double>::infinity() : std::numeric_limits<double>::infinity();
   1.951 +
   1.952 +    return std::numeric_limits<double>::quiet_NaN();
   1.953 +}
   1.954 +
   1.955 +String Decimal::toString() const
   1.956 +{
   1.957 +    switch (m_data.formatClass()) {
   1.958 +    case EncodedData::ClassInfinity:
   1.959 +        return sign() ? "-Infinity" : "Infinity";
   1.960 +
   1.961 +    case EncodedData::ClassNaN:
   1.962 +        return "NaN";
   1.963 +
   1.964 +    case EncodedData::ClassNormal:
   1.965 +    case EncodedData::ClassZero:
   1.966 +        break;
   1.967 +
   1.968 +    default:
   1.969 +        ASSERT_NOT_REACHED();
   1.970 +        return "";
   1.971 +    }
   1.972 +
   1.973 +    StringBuilder builder;
   1.974 +    if (sign())
   1.975 +        builder.append('-');
   1.976 +
   1.977 +    int originalExponent = exponent();
   1.978 +    uint64_t coefficient = m_data.coefficient();
   1.979 +
   1.980 +    if (originalExponent < 0) {
   1.981 +        const int maxDigits = DBL_DIG;
   1.982 +        uint64_t lastDigit = 0;
   1.983 +        while (countDigits(coefficient) > maxDigits) {
   1.984 +            lastDigit = coefficient % 10;
   1.985 +            coefficient /= 10;
   1.986 +            ++originalExponent;
   1.987 +        }
   1.988 +
   1.989 +        if (lastDigit >= 5)
   1.990 +            ++coefficient;
   1.991 +
   1.992 +        while (originalExponent < 0 && coefficient && !(coefficient % 10)) {
   1.993 +            coefficient /= 10;
   1.994 +            ++originalExponent;
   1.995 +        }
   1.996 +    }
   1.997 +
   1.998 +    const String digits = mozToString(coefficient);
   1.999 +    int coefficientLength = static_cast<int>(digits.length());
  1.1000 +    const int adjustedExponent = originalExponent + coefficientLength - 1;
  1.1001 +    if (originalExponent <= 0 && adjustedExponent >= -6) {
  1.1002 +        if (!originalExponent) {
  1.1003 +            builder.append(digits);
  1.1004 +            return builder.toString();
  1.1005 +        }
  1.1006 +
  1.1007 +        if (adjustedExponent >= 0) {
  1.1008 +            for (int i = 0; i < coefficientLength; ++i) {
  1.1009 +                builder.append(digits[i]);
  1.1010 +                if (i == adjustedExponent)
  1.1011 +                    builder.append('.');
  1.1012 +            }
  1.1013 +            return builder.toString();
  1.1014 +        }
  1.1015 +
  1.1016 +        builder.appendLiteral("0.");
  1.1017 +        for (int i = adjustedExponent + 1; i < 0; ++i)
  1.1018 +            builder.append('0');
  1.1019 +
  1.1020 +        builder.append(digits);
  1.1021 +
  1.1022 +    } else {
  1.1023 +        builder.append(digits[0]);
  1.1024 +        while (coefficientLength >= 2 && digits[coefficientLength - 1] == '0')
  1.1025 +            --coefficientLength;
  1.1026 +        if (coefficientLength >= 2) {
  1.1027 +            builder.append('.');
  1.1028 +            for (int i = 1; i < coefficientLength; ++i)
  1.1029 +                builder.append(digits[i]);
  1.1030 +        }
  1.1031 +
  1.1032 +        if (adjustedExponent) {
  1.1033 +            builder.append(adjustedExponent < 0 ? "e" : "e+");
  1.1034 +            builder.appendNumber(adjustedExponent);
  1.1035 +        }
  1.1036 +    }
  1.1037 +    return builder.toString();
  1.1038 +}
  1.1039 +
  1.1040 +bool Decimal::toString(char* strBuf, size_t bufLength) const
  1.1041 +{
  1.1042 +  ASSERT(bufLength > 0);
  1.1043 +  String str = toString();
  1.1044 +  size_t length = str.copy(strBuf, bufLength);
  1.1045 +  if (length < bufLength) {
  1.1046 +    strBuf[length] = '\0';
  1.1047 +    return true;
  1.1048 +  }
  1.1049 +  strBuf[bufLength - 1] = '\0';
  1.1050 +  return false;
  1.1051 +}
  1.1052 +
  1.1053 +Decimal Decimal::zero(Sign sign)
  1.1054 +{
  1.1055 +    return Decimal(EncodedData(sign, EncodedData::ClassZero));
  1.1056 +}
  1.1057 +
  1.1058 +} // namespace WebCore
  1.1059 +

mercurial