// Copyright 2018 The Abseil Authors. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // https://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #ifndef ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ #define ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_ #include #include #include #include #include "absl/base/config.h" #include "absl/strings/ascii.h" #include "absl/strings/internal/charconv_parse.h" #include "absl/strings/string_view.h" namespace absl { ABSL_NAMESPACE_BEGIN namespace strings_internal { // The largest power that 5 that can be raised to, and still fit in a uint32_t. constexpr int kMaxSmallPowerOfFive = 13; // The largest power that 10 that can be raised to, and still fit in a uint32_t. constexpr int kMaxSmallPowerOfTen = 9; ABSL_DLL extern const uint32_t kFiveToNth[kMaxSmallPowerOfFive + 1]; ABSL_DLL extern const uint32_t kTenToNth[kMaxSmallPowerOfTen + 1]; // Large, fixed-width unsigned integer. // // Exact rounding for decimal-to-binary floating point conversion requires very // large integer math, but a design goal of absl::from_chars is to avoid // allocating memory. The integer precision needed for decimal-to-binary // conversions is large but bounded, so a huge fixed-width integer class // suffices. // // This is an intentionally limited big integer class. Only needed operations // are implemented. All storage lives in an array data member, and all // arithmetic is done in-place, to avoid requiring separate storage for operand // and result. // // This is an internal class. Some methods live in the .cc file, and are // instantiated only for the values of max_words we need. template class BigUnsigned { public: static_assert(max_words == 4 || max_words == 84, "unsupported max_words value"); BigUnsigned() : size_(0), words_{} {} explicit constexpr BigUnsigned(uint64_t v) : size_((v >> 32) ? 2 : v ? 1 : 0), words_{static_cast(v & 0xffffffffu), static_cast(v >> 32)} {} // Constructs a BigUnsigned from the given string_view containing a decimal // value. If the input string is not a decimal integer, constructs a 0 // instead. explicit BigUnsigned(absl::string_view sv) : size_(0), words_{} { // Check for valid input, returning a 0 otherwise. This is reasonable // behavior only because this constructor is for unit tests. if (std::find_if_not(sv.begin(), sv.end(), ascii_isdigit) != sv.end() || sv.empty()) { return; } int exponent_adjust = ReadDigits(sv.data(), sv.data() + sv.size(), Digits10() + 1); if (exponent_adjust > 0) { MultiplyByTenToTheNth(exponent_adjust); } } // Loads the mantissa value of a previously-parsed float. // // Returns the associated decimal exponent. The value of the parsed float is // exactly *this * 10**exponent. int ReadFloatMantissa(const ParsedFloat& fp, int significant_digits); // Returns the number of decimal digits of precision this type provides. All // numbers with this many decimal digits or fewer are representable by this // type. // // Analogous to std::numeric_limits::digits10. static constexpr int Digits10() { // 9975007/1035508 is very slightly less than log10(2**32). return static_cast(max_words) * 9975007 / 1035508; } // Shifts left by the given number of bits. void ShiftLeft(int count) { if (count > 0) { const int word_shift = count / 32; if (word_shift >= max_words) { SetToZero(); return; } size_ = (std::min)(size_ + word_shift, max_words); count %= 32; if (count == 0) { // https://gcc.gnu.org/bugzilla/show_bug.cgi?id=warray-bounds // shows a lot of bogus -Warray-bounds warnings under GCC. // This is not the only one in Abseil. #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(14, 0) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Warray-bounds" #endif std::copy_backward(words_, words_ + size_ - word_shift, words_ + size_); #if ABSL_INTERNAL_HAVE_MIN_GNUC_VERSION(14, 0) #pragma GCC diagnostic pop #endif } else { for (int i = (std::min)(size_, max_words - 1); i > word_shift; --i) { words_[i] = (words_[i - word_shift] << count) | (words_[i - word_shift - 1] >> (32 - count)); } words_[word_shift] = words_[0] << count; // Grow size_ if necessary. if (size_ < max_words && words_[size_]) { ++size_; } } std::fill_n(words_, word_shift, 0u); } } // Multiplies by v in-place. void MultiplyBy(uint32_t v) { if (size_ == 0 || v == 1) { return; } if (v == 0) { SetToZero(); return; } const uint64_t factor = v; uint64_t window = 0; for (int i = 0; i < size_; ++i) { window += factor * words_[i]; words_[i] = window & 0xffffffff; window >>= 32; } // If carry bits remain and there's space for them, grow size_. if (window && size_ < max_words) { words_[size_] = window & 0xffffffff; ++size_; } } void MultiplyBy(uint64_t v) { uint32_t words[2]; words[0] = static_cast(v); words[1] = static_cast(v >> 32); if (words[1] == 0) { MultiplyBy(words[0]); } else { MultiplyBy(2, words); } } // Multiplies in place by 5 to the power of n. n must be non-negative. void MultiplyByFiveToTheNth(int n) { while (n >= kMaxSmallPowerOfFive) { MultiplyBy(kFiveToNth[kMaxSmallPowerOfFive]); n -= kMaxSmallPowerOfFive; } if (n > 0) { MultiplyBy(kFiveToNth[n]); } } // Multiplies in place by 10 to the power of n. n must be non-negative. void MultiplyByTenToTheNth(int n) { if (n > kMaxSmallPowerOfTen) { // For large n, raise to a power of 5, then shift left by the same amount. // (10**n == 5**n * 2**n.) This requires fewer multiplications overall. MultiplyByFiveToTheNth(n); ShiftLeft(n); } else if (n > 0) { // We can do this more quickly for very small N by using a single // multiplication. MultiplyBy(kTenToNth[n]); } } // Returns the value of 5**n, for non-negative n. This implementation uses // a lookup table, and is faster then seeding a BigUnsigned with 1 and calling // MultiplyByFiveToTheNth(). static BigUnsigned FiveToTheNth(int n); // Multiplies by another BigUnsigned, in-place. template void MultiplyBy(const BigUnsigned& other) { MultiplyBy(other.size(), other.words()); } void SetToZero() { std::fill_n(words_, size_, 0u); size_ = 0; } // Returns the value of the nth word of this BigUnsigned. This is // range-checked, and returns 0 on out-of-bounds accesses. uint32_t GetWord(int index) const { if (index < 0 || index >= size_) { return 0; } return words_[index]; } // Returns this integer as a decimal string. This is not used in the decimal- // to-binary conversion; it is intended to aid in testing. std::string ToString() const; int size() const { return size_; } const uint32_t* words() const { return words_; } private: // Reads the number between [begin, end), possibly containing a decimal point, // into this BigUnsigned. // // Callers are required to ensure [begin, end) contains a valid number, with // one or more decimal digits and at most one decimal point. This routine // will behave unpredictably if these preconditions are not met. // // Only the first `significant_digits` digits are read. Digits beyond this // limit are "sticky": If the final significant digit is 0 or 5, and if any // dropped digit is nonzero, then that final significant digit is adjusted up // to 1 or 6. This adjustment allows for precise rounding. // // Returns `exponent_adjustment`, a power-of-ten exponent adjustment to // account for the decimal point and for dropped significant digits. After // this function returns, // actual_value_of_parsed_string ~= *this * 10**exponent_adjustment. int ReadDigits(const char* begin, const char* end, int significant_digits); // Performs a step of big integer multiplication. This computes the full // (64-bit-wide) values that should be added at the given index (step), and // adds to that location in-place. // // Because our math all occurs in place, we must multiply starting from the // highest word working downward. (This is a bit more expensive due to the // extra carries involved.) // // This must be called in steps, for each word to be calculated, starting from // the high end and working down to 0. The first value of `step` should be // `std::min(original_size + other.size_ - 2, max_words - 1)`. // The reason for this expression is that multiplying the i'th word from one // multiplicand and the j'th word of another multiplicand creates a // two-word-wide value to be stored at the (i+j)'th element. The highest // word indices we will access are `original_size - 1` from this object, and // `other.size_ - 1` from our operand. Therefore, // `original_size + other.size_ - 2` is the first step we should calculate, // but limited on an upper bound by max_words. // Working from high-to-low ensures that we do not overwrite the portions of // the initial value of *this which are still needed for later steps. // // Once called with step == 0, *this contains the result of the // multiplication. // // `original_size` is the size_ of *this before the first call to // MultiplyStep(). `other_words` and `other_size` are the contents of our // operand. `step` is the step to perform, as described above. void MultiplyStep(int original_size, const uint32_t* other_words, int other_size, int step); void MultiplyBy(int other_size, const uint32_t* other_words) { const int original_size = size_; const int first_step = (std::min)(original_size + other_size - 2, max_words - 1); for (int step = first_step; step >= 0; --step) { MultiplyStep(original_size, other_words, other_size, step); } } // Adds a 32-bit value to the index'th word, with carry. void AddWithCarry(int index, uint32_t value) { if (value) { while (index < max_words && value > 0) { words_[index] += value; // carry if we overflowed in this word: if (value > words_[index]) { value = 1; ++index; } else { value = 0; } } size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } void AddWithCarry(int index, uint64_t value) { if (value && index < max_words) { uint32_t high = value >> 32; uint32_t low = value & 0xffffffff; words_[index] += low; if (words_[index] < low) { ++high; if (high == 0) { // Carry from the low word caused our high word to overflow. // Short circuit here to do the right thing. AddWithCarry(index + 2, static_cast(1)); return; } } if (high > 0) { AddWithCarry(index + 1, high); } else { // Normally 32-bit AddWithCarry() sets size_, but since we don't call // it when `high` is 0, do it ourselves here. size_ = (std::min)(max_words, (std::max)(index + 1, size_)); } } } // Divide this in place by a constant divisor. Returns the remainder of the // division. template uint32_t DivMod() { uint64_t accumulator = 0; for (int i = size_ - 1; i >= 0; --i) { accumulator <<= 32; accumulator += words_[i]; // accumulator / divisor will never overflow an int32_t in this loop words_[i] = static_cast(accumulator / divisor); accumulator = accumulator % divisor; } while (size_ > 0 && words_[size_ - 1] == 0) { --size_; } return static_cast(accumulator); } // The number of elements in words_ that may carry significant values. // All elements beyond this point are 0. // // When size_ is 0, this BigUnsigned stores the value 0. // When size_ is nonzero, is *not* guaranteed that words_[size_ - 1] is // nonzero. This can occur due to overflow truncation. // In particular, x.size_ != y.size_ does *not* imply x != y. int size_; uint32_t words_[max_words]; }; // Compares two big integer instances. // // Returns -1 if lhs < rhs, 0 if lhs == rhs, and 1 if lhs > rhs. template int Compare(const BigUnsigned& lhs, const BigUnsigned& rhs) { int limit = (std::max)(lhs.size(), rhs.size()); for (int i = limit - 1; i >= 0; --i) { const uint32_t lhs_word = lhs.GetWord(i); const uint32_t rhs_word = rhs.GetWord(i); if (lhs_word < rhs_word) { return -1; } else if (lhs_word > rhs_word) { return 1; } } return 0; } template bool operator==(const BigUnsigned& lhs, const BigUnsigned& rhs) { int limit = (std::max)(lhs.size(), rhs.size()); for (int i = 0; i < limit; ++i) { if (lhs.GetWord(i) != rhs.GetWord(i)) { return false; } } return true; } template bool operator!=(const BigUnsigned& lhs, const BigUnsigned& rhs) { return !(lhs == rhs); } template bool operator<(const BigUnsigned& lhs, const BigUnsigned& rhs) { return Compare(lhs, rhs) == -1; } template bool operator>(const BigUnsigned& lhs, const BigUnsigned& rhs) { return rhs < lhs; } template bool operator<=(const BigUnsigned& lhs, const BigUnsigned& rhs) { return !(rhs < lhs); } template bool operator>=(const BigUnsigned& lhs, const BigUnsigned& rhs) { return !(lhs < rhs); } // Output operator for BigUnsigned, for testing purposes only. template std::ostream& operator<<(std::ostream& os, const BigUnsigned& num) { return os << num.ToString(); } // Explicit instantiation declarations for the sizes of BigUnsigned that we // are using. // // For now, the choices of 4 and 84 are arbitrary; 4 is a small value that is // still bigger than an int128, and 84 is a large value we will want to use // in the from_chars implementation. // // Comments justifying the use of 84 belong in the from_chars implementation, // and will be added in a follow-up CL. extern template class BigUnsigned<4>; extern template class BigUnsigned<84>; } // namespace strings_internal ABSL_NAMESPACE_END } // namespace absl #endif // ABSL_STRINGS_INTERNAL_CHARCONV_BIGINT_H_