int128.cc 6.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  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. #include <google/protobuf/stubs/int128.h>
  31. #include <iomanip>
  32. #include <ostream> // NOLINT(readability/streams)
  33. #include <sstream>
  34. namespace google {
  35. namespace protobuf {
  36. const uint128_pod kuint128max = {
  37. static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF)),
  38. static_cast<uint64>(GOOGLE_LONGLONG(0xFFFFFFFFFFFFFFFF))
  39. };
  40. // Returns the 0-based position of the last set bit (i.e., most significant bit)
  41. // in the given uint64. The argument may not be 0.
  42. //
  43. // For example:
  44. // Given: 5 (decimal) == 101 (binary)
  45. // Returns: 2
  46. #define STEP(T, n, pos, sh) \
  47. do { \
  48. if ((n) >= (static_cast<T>(1) << (sh))) { \
  49. (n) = (n) >> (sh); \
  50. (pos) |= (sh); \
  51. } \
  52. } while (0)
  53. static inline int Fls64(uint64 n) {
  54. GOOGLE_DCHECK_NE(0, n);
  55. int pos = 0;
  56. STEP(uint64, n, pos, 0x20);
  57. uint32 n32 = n;
  58. STEP(uint32, n32, pos, 0x10);
  59. STEP(uint32, n32, pos, 0x08);
  60. STEP(uint32, n32, pos, 0x04);
  61. return pos + ((GOOGLE_ULONGLONG(0x3333333322221100) >> (n32 << 2)) & 0x3);
  62. }
  63. #undef STEP
  64. // Like Fls64() above, but returns the 0-based position of the last set bit
  65. // (i.e., most significant bit) in the given uint128. The argument may not be 0.
  66. static inline int Fls128(uint128 n) {
  67. if (uint64 hi = Uint128High64(n)) {
  68. return Fls64(hi) + 64;
  69. }
  70. return Fls64(Uint128Low64(n));
  71. }
  72. // Long division/modulo for uint128 implemented using the shift-subtract
  73. // division algorithm adapted from:
  74. // http://stackoverflow.com/questions/5386377/division-without-using
  75. void uint128::DivModImpl(uint128 dividend, uint128 divisor,
  76. uint128* quotient_ret, uint128* remainder_ret) {
  77. if (divisor == 0) {
  78. GOOGLE_LOG(FATAL) << "Division or mod by zero: dividend.hi=" << dividend.hi_
  79. << ", lo=" << dividend.lo_;
  80. }
  81. if (divisor > dividend) {
  82. *quotient_ret = 0;
  83. *remainder_ret = dividend;
  84. return;
  85. }
  86. if (divisor == dividend) {
  87. *quotient_ret = 1;
  88. *remainder_ret = 0;
  89. return;
  90. }
  91. uint128 denominator = divisor;
  92. uint128 position = 1;
  93. uint128 quotient = 0;
  94. // Left aligns the MSB of the denominator and the dividend.
  95. int shift = Fls128(dividend) - Fls128(denominator);
  96. denominator <<= shift;
  97. position <<= shift;
  98. // Uses shift-subtract algorithm to divide dividend by denominator. The
  99. // remainder will be left in dividend.
  100. while (position > 0) {
  101. if (dividend >= denominator) {
  102. dividend -= denominator;
  103. quotient |= position;
  104. }
  105. position >>= 1;
  106. denominator >>= 1;
  107. }
  108. *quotient_ret = quotient;
  109. *remainder_ret = dividend;
  110. }
  111. uint128& uint128::operator/=(const uint128& divisor) {
  112. uint128 quotient = 0;
  113. uint128 remainder = 0;
  114. DivModImpl(*this, divisor, &quotient, &remainder);
  115. *this = quotient;
  116. return *this;
  117. }
  118. uint128& uint128::operator%=(const uint128& divisor) {
  119. uint128 quotient = 0;
  120. uint128 remainder = 0;
  121. DivModImpl(*this, divisor, &quotient, &remainder);
  122. *this = remainder;
  123. return *this;
  124. }
  125. std::ostream& operator<<(std::ostream& o, const uint128& b) {
  126. std::ios_base::fmtflags flags = o.flags();
  127. // Select a divisor which is the largest power of the base < 2^64.
  128. uint128 div;
  129. std::streamsize div_base_log;
  130. switch (flags & std::ios::basefield) {
  131. case std::ios::hex:
  132. div = static_cast<uint64>(GOOGLE_ULONGLONG(0x1000000000000000)); // 16^15
  133. div_base_log = 15;
  134. break;
  135. case std::ios::oct:
  136. div = static_cast<uint64>(GOOGLE_ULONGLONG(01000000000000000000000)); // 8^21
  137. div_base_log = 21;
  138. break;
  139. default: // std::ios::dec
  140. div = static_cast<uint64>(GOOGLE_ULONGLONG(10000000000000000000)); // 10^19
  141. div_base_log = 19;
  142. break;
  143. }
  144. // Now piece together the uint128 representation from three chunks of
  145. // the original value, each less than "div" and therefore representable
  146. // as a uint64.
  147. std::ostringstream os;
  148. std::ios_base::fmtflags copy_mask =
  149. std::ios::basefield | std::ios::showbase | std::ios::uppercase;
  150. os.setf(flags & copy_mask, copy_mask);
  151. uint128 high = b;
  152. uint128 low;
  153. uint128::DivModImpl(high, div, &high, &low);
  154. uint128 mid;
  155. uint128::DivModImpl(high, div, &high, &mid);
  156. if (high.lo_ != 0) {
  157. os << high.lo_;
  158. os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
  159. os << mid.lo_;
  160. os << std::setw(div_base_log);
  161. } else if (mid.lo_ != 0) {
  162. os << mid.lo_;
  163. os << std::noshowbase << std::setfill('0') << std::setw(div_base_log);
  164. }
  165. os << low.lo_;
  166. std::string rep = os.str();
  167. // Add the requisite padding.
  168. std::streamsize width = o.width(0);
  169. if (width > rep.size()) {
  170. if ((flags & std::ios::adjustfield) == std::ios::left) {
  171. rep.append(width - rep.size(), o.fill());
  172. } else {
  173. rep.insert(static_cast<std::string::size_type>(0),
  174. width - rep.size(), o.fill());
  175. }
  176. }
  177. // Stream the final representation in a single "<<" call.
  178. return o << rep;
  179. }
  180. } // namespace protobuf
  181. } // namespace google