diff options
Diffstat (limited to 'deps/icu-small/source/i18n/double-conversion-diy-fp.h')
-rw-r--r-- | deps/icu-small/source/i18n/double-conversion-diy-fp.h | 59 |
1 files changed, 39 insertions, 20 deletions
diff --git a/deps/icu-small/source/i18n/double-conversion-diy-fp.h b/deps/icu-small/source/i18n/double-conversion-diy-fp.h index 21896851d2..5820abedf3 100644 --- a/deps/icu-small/source/i18n/double-conversion-diy-fp.h +++ b/deps/icu-small/source/i18n/double-conversion-diy-fp.h @@ -50,36 +50,55 @@ namespace double_conversion { // with a uint64 significand and an int exponent. Normalized DiyFp numbers will // have the most significant bit of the significand set. // Multiplication and Subtraction do not normalize their results. -// DiyFp are not designed to contain special doubles (NaN and Infinity). +// DiyFp store only non-negative numbers and are not designed to contain special +// doubles (NaN and Infinity). class DiyFp { public: static const int kSignificandSize = 64; DiyFp() : f_(0), e_(0) {} - DiyFp(uint64_t significand, int exponent) : f_(significand), e_(exponent) {} + DiyFp(const uint64_t significand, const int32_t exponent) : f_(significand), e_(exponent) {} - // this = this - other. + // this -= other. // The exponents of both numbers must be the same and the significand of this - // must be bigger than the significand of other. + // must be greater or equal than the significand of other. // The result will not be normalized. void Subtract(const DiyFp& other) { - ASSERT(e_ == other.e_); - ASSERT(f_ >= other.f_); + DOUBLE_CONVERSION_ASSERT(e_ == other.e_); + DOUBLE_CONVERSION_ASSERT(f_ >= other.f_); f_ -= other.f_; } // Returns a - b. - // The exponents of both numbers must be the same and this must be bigger - // than other. The result will not be normalized. + // The exponents of both numbers must be the same and a must be greater + // or equal than b. The result will not be normalized. static DiyFp Minus(const DiyFp& a, const DiyFp& b) { DiyFp result = a; result.Subtract(b); return result; } - - // this = this * other. - void Multiply(const DiyFp& other); + // this *= other. + void Multiply(const DiyFp& other) { + // Simply "emulates" a 128 bit multiplication. + // However: the resulting number only contains 64 bits. The least + // significant 64 bits are only used for rounding the most significant 64 + // bits. + const uint64_t kM32 = 0xFFFFFFFFU; + const uint64_t a = f_ >> 32; + const uint64_t b = f_ & kM32; + const uint64_t c = other.f_ >> 32; + const uint64_t d = other.f_ & kM32; + const uint64_t ac = a * c; + const uint64_t bc = b * c; + const uint64_t ad = a * d; + const uint64_t bd = b * d; + // By adding 1U << 31 to tmp we round the final result. + // Halfway cases will be rounded up. + const uint64_t tmp = (bd >> 32) + (ad & kM32) + (bc & kM32) + (1U << 31); + e_ += other.e_ + 64; + f_ = ac + (ad >> 32) + (bc >> 32) + (tmp >> 32); + } // returns a * b; static DiyFp Times(const DiyFp& a, const DiyFp& b) { @@ -89,13 +108,13 @@ class DiyFp { } void Normalize() { - ASSERT(f_ != 0); + DOUBLE_CONVERSION_ASSERT(f_ != 0); uint64_t significand = f_; - int exponent = e_; + int32_t exponent = e_; - // This method is mainly called for normalizing boundaries. In general - // boundaries need to be shifted by 10 bits. We thus optimize for this case. - const uint64_t k10MSBits = UINT64_2PART_C(0xFFC00000, 00000000); + // This method is mainly called for normalizing boundaries. In general, + // boundaries need to be shifted by 10 bits, and we optimize for this case. + const uint64_t k10MSBits = DOUBLE_CONVERSION_UINT64_2PART_C(0xFFC00000, 00000000); while ((significand & k10MSBits) == 0) { significand <<= 10; exponent -= 10; @@ -115,16 +134,16 @@ class DiyFp { } uint64_t f() const { return f_; } - int e() const { return e_; } + int32_t e() const { return e_; } void set_f(uint64_t new_value) { f_ = new_value; } - void set_e(int new_value) { e_ = new_value; } + void set_e(int32_t new_value) { e_ = new_value; } private: - static const uint64_t kUint64MSB = UINT64_2PART_C(0x80000000, 00000000); + static const uint64_t kUint64MSB = DOUBLE_CONVERSION_UINT64_2PART_C(0x80000000, 00000000); uint64_t f_; - int e_; + int32_t e_; }; } // namespace double_conversion |