// -*- c++ -*- /**************************************************************** **** **** This file belongs with the course **** Introduction to Scientific Programming in C++/Fortran2003 **** copyright 2016-2023 Victor Eijkhout eijkhout@tacc.utexas.edu **** **** intlib.cxx : header file for the number theory project **** **** division algorithm by Knuth, explained in: **** https://janmr.com/blog/2014/04/basic-multiple-precision-long-division/ **** ****************************************************************/ #include using std::cout; #include using std::pair; #include using std::vector; #include #include "intlib.hpp" /* * Constructors */ template BigInt::BigInt( int init ) { while ( init>0 ) { int d = init%base; _digits.push_back( d ); init = init / base; }; }; template BigInt::BigInt( vector digits ) : _digits(digits) {}; /* * Basic digit twiddling */ template int BigInt::ndigits() const { return _digits.size(); }; template int BigInt::digitbase() const { return base; }; template int BigInt::digit(int i) const { return _digits.at(i); }; template int& BigInt::digit(int i) { return _digits.at(i); }; template int BigInt::leading_digit( int from_back) const { if (_digits.empty()) return 0; else return _digits.at( _digits.size()-1-from_back ); }; template void BigInt::set_leading_digit( int i ) { _digits.push_back(i); }; template void BigInt::shift( int n ) { for ( int i=0; i void BigInt::decr() { if (_digits.at(0)==0) throw( "unimplemented case" ); else _digits.at(0)--; }; template int BigInt::numeric() const { int result{0}; for ( auto d=_digits.rbegin(); d!=_digits.rend(); ++d ) result = base * result + *d; return result; }; /* * Operators to make this look like math */ template bool BigInt::operator==(int compare) const { return numeric()==compare; }; template bool BigInt::operator<( const BigInt& other ) const { return ndigits() BigInt BigInt::operator+( const BigInt& other ) const { if ( *this < other ) return other+(*this); else { BigInt result( *this ); int carry = 0; for ( int id=0; id0) result.set_leading_digit(carry); return result; } }; //! Increase digit id by borrowing from higher digits template void BigInt::borrow( int id ) { assert( id< ndigits()-1 ); if ( _digits.at(id+1)==0 ) borrow(id+1); _digits.at(id+1)--; _digits.at(id) += base; }; template BigInt BigInt::operator-( const BigInt& other ) const { if ( *this < other ) throw("subtraction would yield negative"); else { BigInt result( *this ); for ( int id=0; id=other.ndigits()) break; if (result.digit(id) BigInt BigInt::operator*( int mult ) const { if ( mult==base ) { BigInt result(*this); result.shift(1); return result; } else { BigInt result; int carry = 0; for ( auto d : _digits ) { auto proddigit = mult * d + carry; carry = proddigit / base; result.set_leading_digit( proddigit % base ); } if (carry>0) result.set_leading_digit(carry); return result; } }; template BigInt BigInt::operator*( const BigInt& other ) const { BigInt result; for ( auto d : _digits ) { BigInt line = other * d * base; result = result+line; } return result; }; /* * Dividion algorithm * see: * https://janmr.com/blog/2014/04/basic-multiple-precision-long-division/ */ template BigInt find_qhat( BigInt denom,BigInt numer ) { int n = numer.ndigits(); assert( denom.ndigits()==n+1 ); assert( n>=2 ); int b = base, numer_n1 = denom.leading_digit(1), denom_2 = b*denom.leading_digit() + numer_n1; int u_n2 = denom.digit(n-2), v_n1 = numer.digit(n-1), v_n2 = numer.digit(n-2), qhat = denom_2 / v_n1, rhat = denom_2 % v_n1; if (qhat==b) { cout << "Unimplemented case\n"; throw("Unimplemented case");} while (rhatb*rhat+u_n2) { qhat = qhat-1; rhat = rhat + v_n1; } return BigInt(qhat); }; template pair,BigInt> BigInt:: operator/( const BigInt& denom ) const { // L1: make leading digit big enough if ( denom.leading_digit() < base/2 ) return (*this*2)/(denom*2); else { BigInt numer(*this); BigInt div; for ( int k = ndigits()-denom.ndigits(); k>0; ) { BigInt qhat = find_qhat( numer,denom ); if ( numer < denom*qhat ) qhat.decr(); assert( qhat.ndigits()==1 ); numer = numer - denom*qhat; div.digits().insert( /* pos: */ div.digits().begin(), /* val: */ qhat.digits().front() ); } // L7: if k==0 return {div,div}; // CHECK ON THIS. INCOMPLETE? } }; template class BigInt<10>; template class BigInt<1000>;