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