// File: RLI.cpp // // Version: 0.1 (semi-lamo, might be buggy) // // Implementation of ReallyLongInt methods. // #include #include #include "RLI.h" using namespace std ; // Default constructor // RLI::RLI() { neg = false ; // positive valid = true ; // initialize to zero for (int i = 0 ; i < RLI_SIZE ; i++) { d[i] = 0 ; } } // Alternate Constructor // Data initialized from array of char. // Assumes that A[] has RLI_SIZE elements, ow bad things happen. // RLI::RLI(bool isNeg, unsigned char A[]) { neg = isNeg ; valid = true ; for (int i = 0 ; i < RLI_SIZE ; i++) { d[i] = A[i] ; } } // Accessors // unsigned int RLI::size() const { return RLI_SIZE ; } void RLI::Print() const { if (neg) cout << "- " ; for (int i = RLI_SIZE-1 ; i >= 0 ; i--) { cout << (unsigned short) d[i] << " " ; } } // Comparisons // // Absolute Less Than. // Ignores signs. Checks if |A| < |B|. // bool RLI::AbsLT (const RLI& A, const RLI& B) { for (int i = RLI_SIZE-1 ; i >= 0 ; i--) { if (A.d[i] < B.d[i]) return true ; if (A.d[i] > B.d[i]) return false ; } // |A| == |B| return false ; } // Signed Less Than. // Returns A < B. // bool RLI::LT (const RLI& A, const RLI& B) { // different signs // works even if both are zero if ( A.neg != B.neg ) return A.neg ; // same sign for (int i = RLI_SIZE-1 ; i >= 0 ; i--) { if (A.d[i] < B.d[i]) return !A.neg ; if (A.d[i] > B.d[i]) return A.neg ; } // must be equal return false ; } // Signed Greater Than. // Returns A > B. // bool RLI::GT (const RLI& A, const RLI& B) { return LT(B,A) ; } // Signed Equality. // Returns A == B. // Returns true for +0 vs -0. // bool RLI::EQ (const RLI& A, const RLI& B) { // check absolute value first // for (int i = RLI_SIZE-1 ; i >= 0 ; i--) { if (A.d[i] != B.d[i]) return false ; } // same absolute value and same sign? // if ( A.neg == B.neg ) return true ; // same absolute value, different sign, // but maybe one is +0 and another -0. // for (int i = RLI_SIZE-1 ; i >= 0 ; i--) { if (A.d[i] != 0) return false ; } // all zeroes, different sign return true ; } // Signed Non-equality. // Returns A != B. // Returns false for +0 vs -0. // bool RLI::NE (const RLI& A, const RLI& B) { return !EQ(A,B) ; } // Signed Less Than or Equal To. // Returns A <= B. // bool RLI::LE (const RLI& A, const RLI& B) { return LT(A,B) || EQ(A,B) ; } // Signed Greater Than or Equal To. // Returns A >= B. // bool RLI::GE (const RLI& A, const RLI& B) { return LT(B,A) || EQ(B,A) ; } // Arithmetic // Adds A and B and stores result in C. // Must work even when A or B is C. // void RLI::Add (RLI& C, const RLI& A, const RLI& B) { if (A.neg == B.neg) { // same sign? AbsAdd(C, A, B) ; // might overflow C.neg = A.neg ; } else if (AbsLT(A,B)) { // is |A| < |B|? AbsSub(C, B, A) ; // C = |B| - |A| C.neg = B.neg ; } else { AbsSub(C, A, B) ; // C = |A| - |B| C.neg = A.neg ; } } // Subtracts B from A and stores result in C. // Must work even when A or B is C. // void RLI::Sub (RLI& C, const RLI& A, const RLI& B) { if (A.neg != B.neg) { // different sign? AbsAdd(C,A,B) ; // might overflow C.neg = A.neg ; } else if (AbsLT(A,B)) { // is |A| < |B|? AbsSub(C, B, A) ; C.neg = !B.neg ; } else { AbsSub(C, A, B) ; C.neg = A.neg ; } } // Adds |A| to |B| and stores result in C. // Checks for overflow. // Must work even when A or B is C. // void RLI::AbsAdd (RLI& C, const RLI& A, const RLI& B) { unsigned short x ; unsigned char carry ; carry = 0 ; for (int i = 0 ; i < RLI_SIZE ; i++ ) { x = ( (unsigned short) A.d[i] ) + ( (unsigned short) B.d[i] ) + ( (unsigned short) carry ) ; C.d[i] = x % CHARMAX ; // use bit ops next time carry = x / CHARMAX ; // use shift next time } if (carry > 0) { C.valid = false ; cerr << "An RLI::AbsAdd() overflow occured\n" ; } C.neg = false ; } // Subtracts |B| from |A| and stores result in C. // Must work even when A or B is C. // // This function assumes |A| >= |B|. Bad things happen ow. // Note: result can't overflow if |A| >= |B|, but // we check if |A| >= |B| is violated. // void RLI::AbsSub (RLI& C, const RLI& A, const RLI& B) { unsigned short x, a, b ; unsigned char borrow ; borrow = 0 ; for (int i = 0 ; i < RLI_SIZE ; i++ ) { a = (unsigned short) A.d[i] ; b = (unsigned short) B.d[i] ; if (a >= b + borrow) { x = a - b - borrow ; borrow = 0 ; } else { x = CHARMAX + a - b - borrow ; borrow = 1 ; } C.d[i] = x % CHARMAX ; // use bit ops next time } if (borrow > 0) { C.valid = false ; cerr << "Error: |A| < |B| in RLI::AbsSub() !\n" ; } C.neg = false ; } // Multiplies A by b, stores result in C // // void RLI::MulByChar (RLI& C, const RLI& A, const unsigned char b) { unsigned short x, y, msb, lsb, carry, b2 ; b2 = (unsigned short) b ; for (int i = 0 ; i < RLI_SIZE ; i++) { C.d[i] = 0 ; } for (int i = 0 ; i < RLI_SIZE-1 ; i++) { x = ( (unsigned short) A.d[i] ) * b2 ; msb = x / CHARMAX ; lsb = x % CHARMAX ; y = ( (unsigned short) C.d[i] ) + lsb ; C.d[i] = y % CHARMAX ; carry = y / CHARMAX ; assert(msb + carry < CHARMAX) ; C.d[i+1] = msb + carry ; } // Do last "digit" check for overflow! x = ( (unsigned short) A.d[RLI_SIZE-1] ) * b2 ; if (x / CHARMAX > 0) { cerr << "Overflow in RLI::MulByChar\n" ; C.valid = false ; } y = ( (unsigned short) C.d[RLI_SIZE-1]) + x ; if (y / CHARMAX > 0) { cerr << "Overflow in RLI::MulByChar\n" ; C.valid = false ; } C.d[RLI_SIZE-1] = y % CHARMAX ; C.neg = A.neg ; }