diff options
author | Thales Lima Oliveira <thaleslima.ufu@gmail.com> | 2017-12-19 22:00:05 -0200 |
---|---|---|
committer | Thales Lima Oliveira <thaleslima.ufu@gmail.com> | 2017-12-19 22:00:05 -0200 |
commit | 54bb80251432ff49c967115f8401e7dafc5c57d6 (patch) | |
tree | 3de8eada5c3c601764f60734b71707e95260eeb7 /Project/fparser/mpfr/GmpInt.cc | |
parent | c8193665975686fb8a344bee3dc94914a3d3558a (diff) | |
download | PSP.git-54bb80251432ff49c967115f8401e7dafc5c57d6.tar.gz PSP.git-54bb80251432ff49c967115f8401e7dafc5c57d6.tar.xz PSP.git-54bb80251432ff49c967115f8401e7dafc5c57d6.zip |
Several implementations on math expression block
Diffstat (limited to 'Project/fparser/mpfr/GmpInt.cc')
-rw-r--r-- | Project/fparser/mpfr/GmpInt.cc | 710 |
1 files changed, 710 insertions, 0 deletions
diff --git a/Project/fparser/mpfr/GmpInt.cc b/Project/fparser/mpfr/GmpInt.cc new file mode 100644 index 0000000..490add4 --- /dev/null +++ b/Project/fparser/mpfr/GmpInt.cc @@ -0,0 +1,710 @@ +#include "GmpInt.hh" +#include <gmp.h> +#include <deque> +#include <vector> +#include <cstring> +#include <cctype> + +//=========================================================================== +// Shared data +//=========================================================================== +namespace +{ + unsigned long gIntDefaultNumberOfBits = 256; + + std::vector<char>& intString() + { + static std::vector<char> str; + return str; + } +} + +//=========================================================================== +// Auxiliary structs +//=========================================================================== +struct GmpInt::GmpIntData +{ + unsigned mRefCount; + GmpIntData* nextFreeNode; + mpz_t mInteger; + + GmpIntData(): mRefCount(1), nextFreeNode(0) {} +}; + +class GmpInt::GmpIntDataContainer +{ + std::deque<GmpInt::GmpIntData> mData; + GmpInt::GmpIntData* mFirstFreeNode; + GmpInt::GmpIntData* mConst_0; + + public: + GmpIntDataContainer(): mFirstFreeNode(0), mConst_0(0) {} + + ~GmpIntDataContainer() + { + for(size_t i = 0; i < mData.size(); ++i) + mpz_clear(mData[i].mInteger); + } + + GmpInt::GmpIntData* allocateGmpIntData(unsigned long numberOfBits, + bool initToZero) + { + if(mFirstFreeNode) + { + GmpInt::GmpIntData* node = mFirstFreeNode; + mFirstFreeNode = node->nextFreeNode; + if(initToZero) mpz_set_si(node->mInteger, 0); + ++(node->mRefCount); + return node; + } + + mData.push_back(GmpInt::GmpIntData()); + if(numberOfBits > 0) + mpz_init2(mData.back().mInteger, numberOfBits); + else + mpz_init(mData.back().mInteger); + return &mData.back(); + } + + void releaseGmpIntData(GmpIntData* data) + { + if(--(data->mRefCount) == 0) + { + data->nextFreeNode = mFirstFreeNode; + mFirstFreeNode = data; + } + } + + GmpInt::GmpIntData* const_0() + { + if(!mConst_0) + mConst_0 = allocateGmpIntData(gIntDefaultNumberOfBits, true); + return mConst_0; + } +}; + + +GmpInt::GmpIntDataContainer& GmpInt::gmpIntDataContainer() +{ + static GmpIntDataContainer container; + return container; +} + +//=========================================================================== +// Auxiliary functions +//=========================================================================== +void GmpInt::setDefaultNumberOfBits(unsigned long value) +{ + gIntDefaultNumberOfBits = value; +} + +unsigned long GmpInt::getDefaultNumberOfBits() +{ + return gIntDefaultNumberOfBits; +} + +inline void GmpInt::copyIfShared() +{ + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + GmpIntData* oldData = mData; + mData = gmpIntDataContainer().allocateGmpIntData(0, false); + mpz_set(mData->mInteger, oldData->mInteger); + } +} + + +//=========================================================================== +// Constructors, destructor, assignment +//=========================================================================== +GmpInt::GmpInt(DummyType): + mData(gmpIntDataContainer().allocateGmpIntData(0, false)) +{} + +GmpInt::GmpInt() +{ + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); +} + +GmpInt::GmpInt(long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(unsigned long value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_ui(mData->mInteger, value); + } +} + +GmpInt::GmpInt(int value) +{ + if(value == 0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_si(mData->mInteger, value); + } +} + +GmpInt::GmpInt(double value) +{ + const double absValue = value >= 0.0 ? value : -value; + if(absValue < 1.0) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, value); + } +} + +GmpInt::GmpInt(long double value) +{ + const long double absValue = value >= 0.0L ? value : -value; + if(absValue < 1.0L) + { + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + mpz_set_d(mData->mInteger, double(value)); + } +} + +GmpInt::GmpInt(const GmpInt& rhs): + mData(rhs.mData) +{ + ++(mData->mRefCount); +} + +GmpInt& GmpInt::operator=(const GmpInt& rhs) +{ + if(mData != rhs.mData) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = rhs.mData; + ++(mData->mRefCount); + } + return *this; +} + +GmpInt& GmpInt::operator=(signed long value) +{ + if(value == 0) + { + gmpIntDataContainer().releaseGmpIntData(mData); + mData = gmpIntDataContainer().const_0(); + ++(mData->mRefCount); + } + else + { + if(mData->mRefCount > 1) + { + --(mData->mRefCount); + mData = gmpIntDataContainer().allocateGmpIntData + (gIntDefaultNumberOfBits, false); + } + mpz_set_si(mData->mInteger, value); + } + return *this; +} + +GmpInt::~GmpInt() +{ + gmpIntDataContainer().releaseGmpIntData(mData); +} + + +//=========================================================================== +// Data getters +//=========================================================================== +template<> +void GmpInt::get_raw_mpfr_data<mpz_t>(mpz_t& dest_mpz_t) +{ + std::memcpy(&dest_mpz_t, mData->mInteger, sizeof(mpz_t)); +} + +const char* GmpInt::getAsString(int base) const +{ + intString().resize(mpz_sizeinbase(mData->mInteger, base) + 2); + return mpz_get_str(&intString()[0], base, mData->mInteger); +} + +long GmpInt::toInt() const +{ + return mpz_get_si(mData->mInteger); +} + + +//=========================================================================== +// Modifying operators +//=========================================================================== +GmpInt& GmpInt::operator+=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_add(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator+=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_add_ui(mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator-=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_sub(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator-=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_sub_ui(mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(mData->mInteger, mData->mInteger, -value); + return *this; +} + +GmpInt& GmpInt::operator*=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_mul(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator*=(long value) +{ + copyIfShared(); + mpz_mul_si(mData->mInteger, mData->mInteger, value); + return *this; +} + +GmpInt& GmpInt::operator/=(const GmpInt& rhs) +{ + copyIfShared(); + mpz_tdiv_q(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return *this; +} + +GmpInt& GmpInt::operator/=(long value) +{ + copyIfShared(); + if(value >= 0) + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(mData->mInteger, mData->mInteger, -value); + } + return *this; +} + +GmpInt& GmpInt::operator%=(const GmpInt& rhs) +{ + copyIfShared(); + if(operator<(0)) + { + negate(); + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + negate(); + } + else + { + mpz_mod(mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return *this; +} + +GmpInt& GmpInt::operator%=(long value) +{ + copyIfShared(); + if(value < 0) value = -value; + if(operator<(0)) + { + negate(); + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + negate(); + } + else + { + mpz_mod_ui(mData->mInteger, mData->mInteger, value); + } + return *this; +} + +GmpInt& GmpInt::operator<<=(unsigned long bits) +{ + copyIfShared(); + mpz_mul_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + +GmpInt& GmpInt::operator>>=(unsigned long bits) +{ + copyIfShared(); + mpz_tdiv_q_2exp(mData->mInteger, mData->mInteger, bits); + return *this; +} + + +//=========================================================================== +// Modifying functions +//=========================================================================== +void GmpInt::addProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_addmul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::addProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_addmul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::subProduct(const GmpInt& value1, const GmpInt& value2) +{ + copyIfShared(); + mpz_submul(mData->mInteger, value1.mData->mInteger, value2.mData->mInteger); +} + +void GmpInt::subProduct(const GmpInt& value1, unsigned long value2) +{ + copyIfShared(); + mpz_submul_ui(mData->mInteger, value1.mData->mInteger, value2); +} + +void GmpInt::negate() +{ + copyIfShared(); + mpz_neg(mData->mInteger, mData->mInteger); +} + +void GmpInt::abs() +{ + copyIfShared(); + mpz_abs(mData->mInteger, mData->mInteger); +} + +GmpInt GmpInt::abs(const GmpInt& value) +{ + GmpInt retval(kNoInitialization); + mpz_abs(retval.mData->mInteger, value.mData->mInteger); + return retval; +} + + +//=========================================================================== +// Non-modifying operators +//=========================================================================== +GmpInt GmpInt::operator+(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_add(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator+(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_add_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator-(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_sub(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator-(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_sub_ui(retval.mData->mInteger, mData->mInteger, value); + else + mpz_add_ui(retval.mData->mInteger, mData->mInteger, -value); + return retval; +} + +GmpInt GmpInt::operator*(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_mul(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator*(long value) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_si(retval.mData->mInteger, mData->mInteger, value); + return retval; +} + +GmpInt GmpInt::operator/(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator/(long value) const +{ + GmpInt retval(kNoInitialization); + if(value >= 0) + mpz_tdiv_q_ui(retval.mData->mInteger, mData->mInteger, value); + else + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_tdiv_q_ui(retval.mData->mInteger, retval.mData->mInteger, -value); + } + return retval; +} + +GmpInt GmpInt::operator%(const GmpInt& rhs) const +{ + GmpInt retval(kNoInitialization); + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod(retval.mData->mInteger, + retval.mData->mInteger, rhs.mData->mInteger); + retval.negate(); + } + else + { + mpz_mod(retval.mData->mInteger, mData->mInteger, rhs.mData->mInteger); + } + return retval; +} + +GmpInt GmpInt::operator%(long value) const +{ + GmpInt retval(kNoInitialization); + if(value < 0) value = -value; + if(operator<(0)) + { + mpz_neg(retval.mData->mInteger, mData->mInteger); + mpz_mod_ui(retval.mData->mInteger, retval.mData->mInteger, value); + retval.negate(); + } + else + { + mpz_mod_ui(retval.mData->mInteger, mData->mInteger, value); + } + return retval; +} + +GmpInt GmpInt::operator-() const +{ + GmpInt retval(kNoInitialization); + mpz_neg(retval.mData->mInteger, mData->mInteger); + return retval; +} + +GmpInt GmpInt::operator<<(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_mul_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + +GmpInt GmpInt::operator>>(unsigned long bits) const +{ + GmpInt retval(kNoInitialization); + mpz_tdiv_q_2exp(retval.mData->mInteger, mData->mInteger, bits); + return retval; +} + + +//=========================================================================== +// Comparison operators +//=========================================================================== +bool GmpInt::operator<(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) < 0; +} + +bool GmpInt::operator<(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) < 0; +} + +bool GmpInt::operator<=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) <= 0; +} + +bool GmpInt::operator<=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) <= 0; +} + +bool GmpInt::operator>(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) > 0; +} + +bool GmpInt::operator>(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) > 0; +} + +bool GmpInt::operator>=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) >= 0; +} + +bool GmpInt::operator>=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) >= 0; +} + +bool GmpInt::operator==(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) == 0; +} + +bool GmpInt::operator==(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) == 0; +} + +bool GmpInt::operator!=(const GmpInt& rhs) const +{ + return mpz_cmp(mData->mInteger, rhs.mData->mInteger) != 0; +} + +bool GmpInt::operator!=(long value) const +{ + return mpz_cmp_si(mData->mInteger, value) != 0; +} + +void GmpInt::parseValue(const char* value) +{ + mpz_set_str(mData->mInteger, value, 10); +} + +void GmpInt::parseValue(const char* value, char** endptr) +{ + static std::vector<char> str; + + unsigned startIndex = 0; + while(value[startIndex] && std::isspace(value[startIndex])) ++startIndex; + if(!value[startIndex]) { *endptr = const_cast<char*>(value); return; } + + unsigned endIndex = startIndex; + if(value[endIndex] == '-') ++endIndex; + if(!std::isdigit(value[endIndex])) + { *endptr = const_cast<char*>(value); return; } + if(value[endIndex] == '0' && value[endIndex+1] == 'x') + { + endIndex += 1; + while(std::isxdigit(value[++endIndex])) {} + } + else + { + while(std::isdigit(value[++endIndex])) {} + } + + str.reserve(endIndex - startIndex + 1); + str.assign(value + startIndex, value + endIndex); + str.push_back(0); + + mpz_set_str(mData->mInteger, &str[0], 0); + *endptr = const_cast<char*>(value + endIndex); +} + +GmpInt GmpInt::parseString(const char* str, char** endptr) +{ + GmpInt retval(kNoInitialization); + retval.parseValue(str, endptr); + return retval; +} + +//=========================================================================== +// Operator functions +//=========================================================================== +GmpInt operator+(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, lhs); + else + mpz_sub_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + return retval; +} + +GmpInt operator-(long lhs, const GmpInt& rhs) +{ + GmpInt retval(GmpInt::kNoInitialization); + if(lhs >= 0) + mpz_ui_sub(retval.mData->mInteger, lhs, rhs.mData->mInteger); + else + { + mpz_add_ui(retval.mData->mInteger, rhs.mData->mInteger, -lhs); + mpz_neg(retval.mData->mInteger, retval.mData->mInteger); + } + return retval; +} + +GmpInt operator*(long lhs, const GmpInt& rhs) +{ + return rhs * lhs; +} + +GmpInt operator/(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) / rhs; +} + +GmpInt operator%(long lhs, const GmpInt& rhs) +{ + return GmpInt(lhs) % rhs; +} |