【问题标题】:How can i use unsigned short int and short int to subtract hugeinteger in C++?如何在 C++ 中使用 unsigned short int 和 short int 减去 hugeinteger?
【发布时间】:2016-03-27 03:16:30
【问题描述】:

我尽力用 C++ 编写代码。当我使用 unsigned int 和 int 进行减法时,没关系。但是,使用 unsigned short int 和 short int 进行减法,我遇到了问题。那么我需要在我的代码中做什么?

非常感谢。

测试值:

21758612232416725117133766166700 1758612232416725117155428849047

一开始,我要定义

*这个> op2

绝对。

template< typename T >
HugeInteger< T > HugeInteger< T >::operator-(const HugeInteger &op2)const // subtraction operator; HugeInteger - HugeInteger
{
    int size = integer.getSize();
    int op2Size = op2.integer.getSize();
    int differenceSize = size;
    HugeInteger < T > difference(differenceSize);

    difference = *this;

    Vector<T>::iterator it = difference.integer.begin();

    int counter = 0;

    for (Vector<T>::iterator i = difference.integer.begin(), j = op2.integer.begin(); j < op2.integer.end(); i++, j++) {
        if ((*i - *j - counter) < 10) {
            *i -= (*j + counter);
            counter = 0;
        }
        else {
            *i += 10;
            *i -= (*j + counter);
            counter = 1;
        }
    }

    while (counter == 1) {
        if ((*(it + op2Size) - counter) < 10) {
            *(it + op2Size) -= counter;
            counter = 0;
            op2Size++;
        }

        else {
            *(it + op2Size) += 10;
            *(it + op2Size) -= counter;
            counter = 1;
            op2Size++;
        }
    }

    if (*this == op2) {
        HugeInteger<T> zero(1);
        return zero;
    }

    for (Vector<T>::iterator i = difference.integer.end() - 1; i > difference.integer.begin(); i--) {
        if (*i == 0) {
            differenceSize--;
        }

        else {
            break;
        }
    }

    difference.integer.resize(differenceSize);
    return difference;
}

【问题讨论】:

    标签: c++ c++11 visual-c++ c++14 subtraction


    【解决方案1】:

    您发布的代码中没有足够的信息来确定问题所在。我怀疑这与“短”类型如何转换为 HugeInt 有关。

    下面,我展示了一个与HugeInt 非常相似的类定义。它跟踪一个值的符号,但不幸的是,它只定义了几个成员,足以演示减法。

    这个类有一个疯狂的模板转换构造函数。如果没有其他构造函数可以处理一个类型,它将尝试以与大小无关的方式转换具有该类型的值,就好像它们是某种整数值一样。

    main() 有两个减法运算示例,都涉及一个短值和一个“巨大”值。

    #include <iostream>
    #include <vector>
    #include <string>
    
    // radix-10 arbitrary size integer class
    template<typename T>
    class HugInt {
        // integer digits are stored in a Vector container
        // The example uses the class Vector, derived (statically)
        // from std::vector<T> in order to mimic the class from
        // code in the Question.  Normally, I would just use a std::vector.
        class Vector : public std::vector<T> { // virtual never needed
        public:
            int getSize() const {
                return static_cast<int>(std::vector<T>::size());
        }   };
        // two member variables
        Vector integer;
        int    sign;
    
        // For encapsulation and compactness, this class uses a lot
        // of inline-friend functions.  If considering using your own
        // inline-friends, it must always be called passing at least one 
        // object from the class where the function is defined.
        // Otherwise, the compiler cannot find it.
    
        // compares just the magnitude (unsigned) parts of two HugInts
        // returns a>b:1, a==b:0, a<b:-1
        friend int cmpMagnitude(const HugInt& lh, const HugInt& rh) {
            const int lh_size = lh.integer.getSize();
            const int rh_size = rh.integer.getSize();
            if(lh_size != rh_size) return lh_size > rh_size ? 1 : -1;
            for(int i=lh_size-1; i+1; --i) {
                if(lh.integer[i] != rh.integer[i]) {
                    return lh.integer[i] > rh.integer[i] ? 1 : -1;
            }   }
            return 0;
        }
        // subtract the magnitude of op2 from the magnitude of *this
        // does not take signs into account, but
        // flips sign of *this if op2 has a greater magnitude than *this
        void subMagnitude(const HugInt& op2) {
            const int cm = cmpMagnitude(*this, op2);
            if(cm == 0) {
                // magnitudes are equal, so result is zero
                integer.clear();
                sign = 0;
                return;
            }
            if(cm < 0) {
                // If op2's magnitude is greater than this's
                // subtract this's Magnitude from op2's,
                // then set this to the negated result
                HugInt temp{op2};
                temp.subMagnitude(*this);
                integer = temp.integer;
                sign = -sign;
                return;
            }
            // perform digit-wise Magnitude subtraction
            // here, this's Magnitude is always greater or
            // equal to op2's
            T borrow = 0;
            const int min_size = op2.integer.getSize();
            int i;
            for(i=0; i<min_size; ++i) {
                const T s = op2.integer[i] + borrow;
                if(borrow = (integer[i] < s)) {
                    integer[i] += T(10);
                }
                integer[i] -= s;
            }
            // propagate borrow to upper words (beyond op2's size)
            // i is guaranteed to stay in bounds
            while(borrow) {
                if(borrow = (integer[i] < 1)) {
                    integer[i] += T(10);
                }
                --integer[i++];
            }
            // remove zeroes at end until a nonzero
            // digit is encountered or the vector is empty
            while(!integer.empty() && !integer.back()) {
                integer.pop_back();
            }
            // if the vector is empty after removing zeroes,
            // the object's value is 0, fixup the sign
            if(integer.empty()) sign = 0;
        }
    
        void addMagnitude(const HugInt& op2) {
            std::cout << "addMagnitude called but not implemented\n";
        }
        // get_sign generically gets a value's sign as an int
        template <typename D>
        static int get_sign(const D& x) { return int(x > 0) - (x < 0); }
    public:
        HugInt() : sign(0) {}  // Default ctor
        // Conversion ctor for template type
        // Handles converting from any type not handled elsewhere
        // Assumes D is some kind of integer type
        // To be more correct, narrow the set of types this overload will handle,
        // either by replacing with overloads for specific types,
        // or use <type_traits> to restrict it to integer types.
        template <typename D>
        HugInt(D src) : sign(get_sign(src)) {
            // if src is negative, make absolute value to store magnitude in Vector
            if(sign < 0) src = D(0)-src; // subtract from zero prevents warning with unsigned D
            // loop gets digits from least- to most-significant 
            // Repeat until src is zero: get the low digit, with src (mod 10)
            // then divide src by 10 to shift all digits down one place.
            while(src >= 1) {
                integer.push_back(T(src % D(10)));
                src /= D(10);
        }   }
        // converting floating-point values will cause an error if used with the integer modulo
        // operator (%). New overloads could use fmod. But for a shorter example, do something cheesy:
        HugInt(double src) : HugInt(static_cast<long long>(src)) {}
        HugInt(float src)  : HugInt(static_cast<long long>(src)) {}
        // conversion ctor from std::string
        HugInt(const std::string& str) : sign(1) {
            for(auto c : str) {
                switch(c) {
                    // for simple, short parsing logic, a '-'
                    // found anywhere in the parsed value will
                    // negate the sign.  If the '-' count is even,
                    // the result will be positive.
                    case '-': sign = -sign; break;
                    case '+': case ' ': case '\t': break; // '+', space and tab ignored
                    case '0': if(integer.empty()) break;  // ignore leading zeroes or fallthrough
                    case '1': case '2': case '3': case '4': case '5':
                    case '6': case '7': case '8': case '9':
                        integer.insert(integer.begin(), T(c - '0'));
                        break;  
            }   }
            if(integer.empty()) sign = 0; // fix up zero value if no digits between '1' and '9' found
        }
        // conversion ctor from C-String (dispatches to std::string ctor)
        HugInt(const char* str) : HugInt(std::string(str)) {}
    
        // The default behavior, using value semantics to copy the
        // two data members, is correct for our copy/move ctors/assigns
        HugInt(const HugInt& src)              = default;
        HugInt& operator = (const HugInt& src) = default;
        // some "C++11" compilers refuse to default the moves
        // HugInt(HugInt&& src)                   = default;
        // HugInt& operator = (HugInt&& src)      = default;
    
        // cmp(a, b) returns 1 if a>b, 0 if a==b or -1 if a<b
        friend int cmp(const HugInt& lh, const HugInt& rh) {
            if(lh.sign != rh.sign) return lh.sign > rh.sign ? 1 : -1;
            const int cmpmag = cmpMagnitude(lh, rh);
            return lh.sign < 0 ? -cmpmag : cmpmag;
        }
        friend bool operator == (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) == 0;
        }
        friend bool operator != (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) != 0;
        }
        friend bool operator > (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) == 1;
        }
        friend bool operator < (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) == -1;
        }
        friend bool operator >= (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) != -1;
        }
        friend bool operator <= (const HugInt& lh, const HugInt& rh) {
            return cmp(lh, rh) != 1;
        }
        // negate operator
        HugInt operator - () const {
            HugInt neg;
            neg.integer = integer;
            neg.sign = -sign;
            return neg;
        }
        // subtract-assign operator
        HugInt& operator -= (const HugInt &op2) {
            if(op2.sign == 0) { // op2 is zero, do nothing
                return *this;
            }
            if(sign == 0) { // *this is zero, set *this to negative op2
                integer = op2.integer;
                sign = -op2.sign;
                return *this;
            }
            if(sign == op2.sign) { // same signs: use magnitude subtratction
                subMagnitude(op2);
                return *this;
            }
            // opposite signs here: needs magnitude addition (but not implemented)
            addMagnitude(op2);
            return *this;
        }
    
        friend HugInt operator - (const HugInt& lh, const HugInt& rh) {
            // a - b uses the -= operator to avoid duplicate code
            HugInt result{lh};
            return result -= rh;
        }
    
        // overload stream output operator for HugInt values
        friend std::ostream& operator << (std::ostream& os, const HugInt& hi) {
            // assumes decimal output and class radix is 10
            if(hi.integer.getSize() == 0) return os << '0';
            if(hi.sign < 0) os << '-';
            for(int i=hi.integer.getSize()-1; i+1; --i) {
                os << char('0' + int(hi.integer[i]));
            }
            return os;
        }
    };
    
    int main() {
        using HugeInt = HugInt<char>;
        {
            HugeInt a = "21758612232416725117133766166700 1758612232416725117155428849047";
            unsigned short b = 55427;
            HugeInt c = a - b;
            std::cout << a << " - " << b << " = \n" << c << '\n';
        }
            std::cout << '\n';
        {
            short a = 6521;
            HugeInt b = 1234567;
            HugeInt c = a - b;
            std::cout << a << " - " << b << " = \n" << c << '\n';
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-07-11
      • 1970-01-01
      • 2013-09-03
      • 2020-01-10
      相关资源
      最近更新 更多