| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473 |
- // Copyright (c) 2008-2023 the Urho3D project
- // License: MIT
- #include "BigInt.h"
- #include "../Container/Pair.h"
- #include "../Core/StringUtils.h"
- #include "../DebugNew.h"
- namespace Urho3D
- {
- #if true
- static constexpr BigInt::Digit BASE = 1000'000'000; // 10^9
- // Number of decimal digits in each magnitude_ element
- static constexpr i32 BASE_DIGITS = 9;
- #else // For tests
- static constexpr BigInt::Digit BASE = 10;
- static constexpr i32 BASE_DIGITS = 1;
- #endif
- // Compare magnitudes
- static bool FirstIsLess(const Vector<BigInt::Digit>& first, const Vector<BigInt::Digit>& second)
- {
- if (first.Size() != second.Size())
- return first.Size() < second.Size();
- for (i32 i = first.Size() - 1; i >= 0; --i)
- {
- if (first[i] != second[i])
- return first[i] < second[i];
- }
- return false; // first == b
- }
- // a + b
- static Vector<BigInt::Digit> SumMagnitudes(const Vector<BigInt::Digit>& a, const Vector<BigInt::Digit>& b)
- {
- Vector<BigInt::Digit> ret;
- i32 maxSize = Max(a.Size(), b.Size());
- ret.Resize(maxSize, 0);
- for (i32 i = 0; i < maxSize; ++i)
- {
- BigInt::Digit a_element = i < a.Size() ? a[i] : 0;
- BigInt::Digit b_element = i < b.Size() ? b[i] : 0;
- BigInt::Digit sum = a_element + b_element;
- ret[i] += sum; // ret[i] can be not zero
- while (ret[i] >= BASE)
- {
- ret[i] -= BASE; // Use div & mod instead loop?
- if (i + 1 < ret.Size())
- ++ret[i + 1];
- else
- ret.Push(1);
- }
- }
- return ret;
- }
- // a - b (a must be >= b)
- static Vector<BigInt::Digit> DiffMagnitudes(const Vector<BigInt::Digit>& a, const Vector<BigInt::Digit>& b)
- {
- Vector<BigInt::Digit> ret;
- ret.Resize(a.Size(), 0);
- for (i32 i = 0; i < a.Size(); ++i)
- {
- BigInt::Digit a_element = a[i];
- BigInt::Digit b_element = i < b.Size() ? b[i] : 0;
- BigInt::Digit diff = a_element - b_element;
- ret[i] += diff; // ret[i] can be not zero
- while (ret[i] < 0)
- {
- ret[i] += BASE;
- assert(i + 1 < ret.Size());
- --ret[i + 1];
- }
- }
- // Remove leading zeros
- while (ret.Size() >= 2 && ret.Back() == 0)
- ret.Pop();
- return ret;
- }
- // Return quotient and remainder.
- // If denominator == 0, then return {0, 0}
- Pair<BigInt, BigInt> DivMod(BigInt numerator, BigInt denominator)
- {
- if (denominator == 0)
- return {0, 0};
- BigInt absNum = Abs(numerator);
- BigInt absDenom = Abs(denominator);
- BigInt quotient = 0;
- BigInt remainder = absNum;
- // The Simplest and slowest way
- while (remainder >= absDenom)
- {
- ++quotient;
- remainder -= absDenom;
- String strQ = quotient.ToString();
- String strRem = remainder.ToString();
- int a = 0;
- }
- // https://en.cppreference.com/w/cpp/language/operator_arithmetic
- // (a/b)*b + a%b == a
- // 7/3 = {2, 1} | 2*3 + 1 == 7
- // -7/3 = {-2, -1} | -2*3 + -1 == -7
- // 7/-3 = {-2, 1} | -2*-3 + 1 == 7
- // -7/-3 = {2, -1} | 2*-3 + -1 == -7
- if (numerator.IsPositive() != denominator.IsPositive())
- quotient = -quotient;
- if (numerator.IsNegative())
- remainder = -remainder;
- return {quotient, remainder};
- }
- BigInt::BigInt()
- {
- // Init as zero
- positive_ = true;
- magnitude_.Resize(1, 0);
- }
- BigInt::BigInt(const String& str)
- {
- if (str.Empty())
- {
- // Init as zero
- positive_ = true;
- magnitude_.Resize(1, 0);
- return;
- }
- i32 firstDigitPos;
- if (str[0] == '-')
- {
- positive_ = false;
- firstDigitPos = 1;
- }
- else if (str[0] == '+')
- {
- positive_ = true;
- firstDigitPos = 1;
- }
- else
- {
- positive_ = true;
- firstDigitPos = 0;
- }
- // Skip leading zeros
- for (i32 i = firstDigitPos; i < (i32)str.Length(); ++i)
- {
- if (str[i] != '0')
- break;
- ++firstDigitPos;
- }
- i32 lastDigitPos = -1;
- for (i32 i = firstDigitPos; i < (i32)str.Length(); ++i)
- {
- if (!IsDigit(str[i]))
- break;
- lastDigitPos = i;
- }
- if (lastDigitPos == -1)
- {
- // Init as zero
- positive_ = true;
- magnitude_.Resize(1, 0);
- return;
- }
- i32 numDigits = lastDigitPos - firstDigitPos + 1;
- magnitude_.Reserve(numDigits / BASE_DIGITS + 1);
- // Retrieve chunks of 9 digits in reverse order and save to single i32
- i32 i = lastDigitPos - BASE_DIGITS + 1;
- for (; i > firstDigitPos; i -= BASE_DIGITS)
- {
- String chunk = str.Substring(i, BASE_DIGITS);
- magnitude_.Push(ToI64(chunk)); // To Digit
- }
- String lastChunk = str.Substring(firstDigitPos, BASE_DIGITS + i - firstDigitPos);
- magnitude_.Push(ToI64(lastChunk)); // To Digit
- }
- BigInt::BigInt(i32 value)
- {
- positive_ = (value >= 0);
- value = Urho3D::Abs(value);
- while (value != 0)
- {
- Digit mod = value % BASE;
- magnitude_.Push(mod);
- value /= BASE;
- }
- if (!magnitude_.Size()) // value == 0
- magnitude_.Push(0);
- }
- BigInt::BigInt(i64 value)
- {
- positive_ = (value >= 0);
- value = Urho3D::Abs(value);
- while (value != 0)
- {
- Digit mod = value % BASE;
- magnitude_.Push(mod);
- value /= BASE;
- }
- if (!magnitude_.Size()) // value == 0
- magnitude_.Push(0);
- }
- BigInt::BigInt(u32 value)
- {
- positive_ = true;
- while (value != 0)
- {
- Digit mod = value % BASE;
- magnitude_.Push(mod);
- value /= BASE;
- }
- if (!magnitude_.Size()) // value == 0
- magnitude_.Push(0);
- }
- BigInt::BigInt(u64 value)
- {
- positive_ = true;
- while (value != 0)
- {
- Digit mod = (Digit)(value % BASE);
- magnitude_.Push(mod);
- value /= BASE;
- }
- if (!magnitude_.Size()) // value == 0
- magnitude_.Push(0);
- }
- bool BigInt::IsZero() const
- {
- assert(magnitude_.Size() > 0);
- if (magnitude_.Size() == 1 && magnitude_[0] == 0)
- {
- assert(positive_);
- return true;
- }
- return false;
- }
- bool BigInt::operator <(const BigInt& rhs) const
- {
- if (positive_ != rhs.positive_)
- return !positive_;
- if (positive_)
- return FirstIsLess(magnitude_, rhs.magnitude_);
- else
- return FirstIsLess(rhs.magnitude_, magnitude_);
- }
- String BigInt::ToString() const
- {
- assert(magnitude_.Size() > 0);
- String ret;
- if (!positive_)
- ret = "-";
- // Beginning of the number without leading zeros
- i32 i = (i32)magnitude_.Size() - 1;
- ret += String(magnitude_[i]);
- --i;
- // Another chunks with leading zeros
- for (; i >= 0; --i)
- {
- String str(magnitude_[i]);
- if (str.Length() < BASE_DIGITS)
- {
- String zeros('0', BASE_DIGITS - str.Length());
- str = zeros + str;
- }
- ret += str;
- }
- return ret;
- }
- BigInt BigInt::operator +(const BigInt& rhs) const
- {
- BigInt ret;
- if (positive_ == rhs.positive_)
- {
- ret.positive_ = positive_;
- ret.magnitude_ = SumMagnitudes(magnitude_, rhs.magnitude_);
- }
- else
- {
- if (FirstIsLess(magnitude_, rhs.magnitude_))
- {
- ret.positive_ = rhs.positive_;
- ret.magnitude_ = DiffMagnitudes(rhs.magnitude_, magnitude_);
- }
- else
- {
- ret.positive_ = positive_;
- ret.magnitude_ = DiffMagnitudes(magnitude_, rhs.magnitude_);
- }
- }
- return ret;
- }
- BigInt BigInt::operator -(const BigInt& rhs) const
- {
- BigInt ret;
- if (positive_ != rhs.positive_)
- {
- ret.positive_ = positive_;
- ret.magnitude_ = SumMagnitudes(magnitude_, rhs.magnitude_);
- }
- else
- {
- if (FirstIsLess(magnitude_, rhs.magnitude_))
- {
- ret.positive_ = !rhs.positive_;
- ret.magnitude_ = DiffMagnitudes(rhs.magnitude_, magnitude_);
- }
- else
- {
- ret.positive_ = positive_;
- ret.magnitude_ = DiffMagnitudes(magnitude_, rhs.magnitude_);
- }
- }
- return ret;
- }
- BigInt BigInt::operator *(const BigInt& rhs) const
- {
- BigInt ret;
- ret.magnitude_.Resize(magnitude_.Size() + rhs.magnitude_.Size(), 0);
- if (positive_ == rhs.positive_)
- ret.positive_ = true;
- else
- ret.positive_ = false;
- for (i32 this_index = 0; this_index < magnitude_.Size(); ++this_index)
- {
- for (i32 rhs_index = 0; rhs_index < rhs.magnitude_.Size(); ++rhs_index)
- ret.magnitude_[this_index + rhs_index] += magnitude_[this_index] * rhs.magnitude_[rhs_index];
- }
- for (i32 i = 0; i < ret.magnitude_.Size() - 1; ++i)
- {
- ret.magnitude_[i + 1] += ret.magnitude_[i] / BASE;
- ret.magnitude_[i] %= BASE;
- }
- // Remove leading zeros
- while (ret.magnitude_.Size() >= 2 && ret.magnitude_.Back() == 0)
- ret.magnitude_.Pop();
- return ret;
- }
- BigInt BigInt::operator /(const BigInt& rhs) const
- {
- Pair<BigInt, BigInt> divMod = DivMod(*this, rhs);
- return divMod.first_;
- }
- BigInt BigInt::operator %(const BigInt& rhs) const
- {
- Pair<BigInt, BigInt> divMod = DivMod(*this, rhs);
- return divMod.second_;
- }
- BigInt BigInt::operator -() const
- {
- BigInt ret = *this;
- if (!ret.IsZero())
- ret.positive_ = !ret.positive_;
- return ret;
- }
- BigInt& BigInt::operator +=(const BigInt& rhs)
- {
- BigInt result = *this + rhs;
- Swap(this->positive_, result.positive_);
- Swap(this->magnitude_, result.magnitude_);
- return *this;
- }
- BigInt& BigInt::operator -=(const BigInt& rhs)
- {
- BigInt result = *this - rhs;
- Swap(this->positive_, result.positive_);
- Swap(this->magnitude_, result.magnitude_);
- return *this;
- }
- BigInt& BigInt::operator *=(const BigInt& rhs)
- {
- BigInt result = *this * rhs;
- Swap(this->positive_, result.positive_);
- Swap(this->magnitude_, result.magnitude_);
- return *this;
- }
- BigInt& BigInt::operator /=(const BigInt& rhs)
- {
- BigInt result = *this / rhs;
- Swap(this->positive_, result.positive_);
- Swap(this->magnitude_, result.magnitude_);
- return *this;
- }
- BigInt& BigInt::operator %=(const BigInt& rhs)
- {
- BigInt result = *this % rhs;
- Swap(this->positive_, result.positive_);
- Swap(this->magnitude_, result.magnitude_);
- return *this;
- }
- } // namespace Urho3D
|