Пример #1
0
        public static MPUnit Sub(MPUnit minuend, MPUnit subtrahend)
        {
            // subtrahend >= minuend
            int compares = minuend.CompareTo(subtrahend);
            if(compares == 0)
            {
                MPUnit retval = new MPUnit();
                retval.numDigits = minuend.numDigits;
                return retval;
            }

            if(compares<0)
                throw new ArithmeticException();

            MPUnit difference = new MPUnit();
            int maxdigits = minuend.Digits;
            subtrahend.Digits=maxdigits;

            int carry=0;

            for(int i=0; i<maxdigits; i++)
            {
                int resdigit = minuend[i]-subtrahend[i]+carry;
                if(resdigit<0)
                {
                    resdigit+=MPUnit.BASE;
                    carry=-1;
                }
                else
                    carry=0;
                difference[i]=(UInt16)resdigit;
            }

            while(difference.Digits >0 && difference[difference.Digits-1]==0)
            {	difference.Digits = difference.Digits-1;  }

            // underflow exception
            if(carry==-1)
                throw new ArithmeticException();

            return difference;
        }
Пример #2
0
        /// <summary>
        /// Divides current MPUnit by mpu1, Quotient in q, Remainder in r
        /// </summary>
        /// <param name="mpu1"></param>
        /// <param name="q"></param>
        /// <param name="r"></param>
        /// <returns></returns>
        public static void Div(MPUnit dividend, MPUnit divisor, ref MPUnit q, ref MPUnit r)
        {
            MPUnit mpuInter = new MPUnit();
            MPUnit u = new MPUnit(dividend);
            MPUnit v = new MPUnit(divisor);
            q = new MPUnit();

            // Can't divide by zero
            if(v.numDigits == 0)
                throw new ArgumentException();

            // dividing zero by something else equals zero
            if(u.numDigits == 0)
            {
                q.numDigits=0;
                r.numDigits=0;
                return;
            }

            // if the v only has one digit, use the simple routine
            // BUGBUG, how about pretending v has two digits, then postshifting?
            if(v.numDigits == 1)
            {
                Div(u, v[0], ref q , ref r);
                return;
            }

            // ok, long route
            // normalize to give better qhat estimates
            // this raises number of digits in u by one
            // (top digit may be zero) and does not raise the number
            // of digits in v (since we've just scaled its top
            // digit to be between BASE/2 and BASE
            UInt16 scale = 1;

            int n = v.Digits;
            int m = u.Digits-n;

            int v_msd = v[n-1];

            // scale up v
            while(v_msd < BASE/2)
            {
                v_msd <<= 1;
                scale <<= 1;
            }

            // if no shift occurs, or if the multiplication
            // doesn't cause a carry into a higher digit
            // we will add an additional 0 digit anyway
            int u_inc_digits = u.Digits+1;

            if(scale != 1)
            {
                // This may or may not increment the number of digits in u...
                // must check this
                int digits = u.Digits;
                u = MPUnit.Mult(u,scale);
                v = MPUnit.Mult(v,scale);
            }

            u.Digits=u_inc_digits;

            // initialize j
            for(int j=m; j>=0; j--)
            {
                // generate qhat
                // From Knuth (Uj+nB + Uj+n-1)/(Vn-1)
                long uhat = (((long)u[j+n]) << 16) + ((long)u[j+n-1]) ;
                long vhat = (long)v[n-1];
                long qhat = uhat  / vhat ;
                long rhat = uhat - (qhat * vhat);

                long test1 = qhat*v[n-2];
                long test2 = (BASE * rhat) + ( (j+n-2) >=0 ? (int)u[j+n-2] : (int)0);

                // Make sure we didn't overflow in
                // creating the test values
                Debug.Assert(test1>=0 && test2>=0);

                // decrease qhat by one if it is BASE or test fails
                if(qhat == BASE || test1 > test2)
                {
                    qhat--;
                    rhat += v[n-1];
                    test1 = qhat*v[n-2];
                    test2 = (BASE * rhat) + ( (j+n-2) >=0 ? (int)u[j+n-2] : (int)0);

                    // qhat is still 1 too great
                    if(rhat < BASE && (qhat == BASE || test1>test2))
                    {
                        qhat--;
                    }

                }

                Debug.Assert(qhat < BASE && qhat>=0 && rhat>=0);

                // Multiply and subtract
                // subtract term from top term.Digits digits of u
                // easiest done as a shift of term?

                MPUnit term = MPUnit.Mult(v,(ushort)qhat);
                term.ASL(j);

                // if the result would be negative, then
                // we oopsd again
                if(u.CompareTo(term)<0)
                {
                    qhat--;
                    term = MPUnit.Mult(v,(ushort)qhat);
                    term.ASL(j);
                }

                u = MPUnit.Sub(u,term);

                // set quotient digit
                q[j]=(ushort)qhat;

            }

            q.Trim();
            r = MPUnit.Sub(dividend,MPUnit.Mult(divisor,q));
            r.Trim();

            return;
        }