mfbt/decimal/Decimal.cpp

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

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

mercurial