📄 vnl_bignum.cxx
字号:
rt_pos = 0;
char c = next(s,is);
while (c == ' ' || c == '\t' || c == '\n' || c == '\r') c = next(s,is);
if (c == '+' || c == '-') c = next(s,is);
if (c != '0') return false;
while (c >= '0' && c <= '7') c = next(s,is);
if (c == 'l' || c == 'L') c = next(s,is);
if (rt_pos > 0) rt[++rt_pos] = '\0';
return is ? true : c == '\0';
}
static bool is_plus_inf(const char* s, vcl_istream** is = 0)
{
rt_pos = 0;
char c = next(s,is);
while (c == ' ' || c == '\t' || c == '\n' || c == '\r') c = next(s,is);
if (c == '+') c = next(s,is);
if (c != 'I') return false; c = next(s,is);
if (c != 'n') return false; c = next(s,is);
if (c != 'f') return false; c = next(s,is);
if (c == 'i') c = next(s,is);
if (c == 'n') c = next(s,is);
if (c == 'i') c = next(s,is);
if (c == 't') c = next(s,is);
if (c == 'y') c = next(s,is);
if (rt_pos > 0) rt[++rt_pos] = '\0';
return is ? true : c == '\0';
}
static bool is_minus_inf(const char* s, vcl_istream** is = 0)
{
rt_pos = 0;
char c = next(s,is);
while (c == ' ' || c == '\t' || c == '\n' || c == '\r') c = next(s,is);
if (c != '-') return false; c = next(s,is);
if (c != 'I') return false; c = next(s,is);
if (c != 'n') return false; c = next(s,is);
if (c != 'f') return false; c = next(s,is);
if (c == 'i') c = next(s,is);
if (c == 'n') c = next(s,is);
if (c == 'i') c = next(s,is);
if (c == 't') c = next(s,is);
if (c == 'y') c = next(s,is);
if (rt_pos > 0) rt[++rt_pos] = '\0';
return is ? true : c == '\0';
}
#endif // new implementation - PVr
//: Creates a vnl_bignum from the character string representation.
vnl_bignum::vnl_bignum (const char *s)
: count(0), sign(1), data(0)
{
// decimal: "^ *[-+]?[1-9][0-9]*$"
// exponential: "^ *[-+]?[1-9][0-9]*[eE][+]?[0-9]+$"
// hexadecimal: "^ *[-+]?0[xX][0-9a-fA-F]+$"
// octal: "^ *[-+]?0[0-7]*$"
// infinity: "^ *[-+]?Inf(inity)?$"
if (is_plus_inf(s))
sign=1,count=1,data=new Data[1],data[0]=0;
else if (is_minus_inf(s))
sign=-1,count=1,data=new Data[1],data[0]=0;
else if (is_decimal(s)) // If string is decimal
this->dtoBigNum(s); // convert decimal to vnl_bignum
else if (is_exponential(s)) // If string is exponential
this->exptoBigNum(s); // convert exp. to vnl_bignum
else if (is_hexadecimal(s)) // If string is hex,
this->xtoBigNum(s); // convert hex to vnl_bignum
else if (is_octal(s)) // If string is octal
this->otoBigNum(s); // convert octal to vnl_bignum
else { // Otherwise
vcl_cerr << "Cannot convert string " << s << " to vnl_bignum\n";
}
}
//: Reads a vnl_bignum from a stream
vcl_istream& operator>> (vcl_istream& is, vnl_bignum& x)
{
// decimal: "^ *[-+]?[1-9][0-9]*$"
// exponential: "^ *[-+]?[1-9][0-9]*[eE][+]?[0-9]+$"
// hexadecimal: "^ *[-+]?0[xX][0-9a-fA-F]+$"
// octal: "^ *[-+]?0[0-7]*$"
vcl_istream* isp = &is;
rt[0] = '\0';
if (is_plus_inf(rt,&isp))
x.sign=1,x.count=1,x.data=new Data[1],x.data[0]=0;
else if (is_minus_inf(rt,&isp))
x.sign=-1,x.count=1,x.data=new Data[1],x.data[0]=0;
if (is_exponential(rt,&isp)) // If input stream string is exponential
x.exptoBigNum(rt); // convert exp. to vnl_bignum
else if (is_decimal(rt,&isp)) // If string is decimal
x.dtoBigNum(rt); // convert decimal to vnl_bignum
else if (is_hexadecimal(rt,&isp)) // If string is hex,
x.xtoBigNum(rt); // convert hex to vnl_bignum
else if (is_octal(rt,&isp)) // If string is octal
x.otoBigNum(rt); // convert octal to vnl_bignum
else { // Otherwise
vcl_cerr << "Cannot convert string " << rt << " to vnl_bignum\n";
x = 0L;
}
return is; // FIXME - should probably push back read characters to istream
}
//: Copies the contents of vnl_bignum b.
vnl_bignum::vnl_bignum (const vnl_bignum& b)
: count(b.count), sign(b.sign)
{
this->data = b.data ? new Data[b.count] : 0; // Allocate data if necessary
for (Counter i = 0; i < this->count; ++i) // Copy b data
this->data[i] = b.data[i];
}
//: Frees space for vnl_bignum.
vnl_bignum::~vnl_bignum ()
{
delete [] this->data; this->count = 0; // Delete any allocated data
}
//: Copies rhs vnl_bignum to lhs vnl_bignum.
vnl_bignum& vnl_bignum::operator= (const vnl_bignum& rhs)
{
if (this != &rhs) { // Avoid self-assignment
delete [] this->data; // Delete existing data
this->count = rhs.count; // Copy rhs's count
this->data = rhs.data ? new Data[rhs.count] : 0; // Allocate data if necessary
for (Counter i = 0; i < rhs.count; ++i) // Copy rhs's data
this->data[i] = rhs.data[i];
this->sign = rhs.sign; // Copy rhs's sign
}
return *this; // Return reference
}
//: Returns the negation of a vnl_bignum.
vnl_bignum vnl_bignum::operator- () const
{
vnl_bignum neg(*this);
if (neg.count) // So long as this is non-zero
neg.sign = -neg.sign; // Flip its sign
return neg;
}
//: Prefix increment. Increments a vnl_bignum by 1, and returns it.
vnl_bignum& vnl_bignum::operator++ ()
{
return *this = *this + 1L;
}
//: Prefix decrement. Decrements a vnl_bignum by 1, and returns it.
vnl_bignum& vnl_bignum::operator-- ()
{
return *this = *this - 1L;
}
//: Adds two vnl_bignums, and returns new sum.
vnl_bignum vnl_bignum::operator+(const vnl_bignum& b) const
{
// Infinity arithmetic:
assert (! b.is_minus_infinity() || ! this->is_plus_infinity() ); // +Inf-Inf
assert (! b.is_plus_infinity() || ! this->is_minus_infinity() ); // -Inf+Inf
if (b.is_infinity()) { return b; }
if (this->is_infinity()) { return *this; }
vnl_bignum sum; // Init sum to zero
if (this->sign == b.sign) { // If both have same sign
add(*this,b,sum); // Do simple addition
sum.sign = this->sign; // Attach proper sign
}
else { // Else different signs
int mag = magnitude_cmp(*this,b); // Determine relative sizes
if (mag > 0) { // If abs(*this) > abs(b)
subtract(*this,b,sum); // sum = *this - b
sum.sign = this->sign; // Sign of sum follows *this
}
else if (mag < 0) { // Else if abs(*this) < abs(b)
subtract(b,*this,sum); // sum = b - *this
sum.sign = b.sign; // Sign of sum follows b
} // (Else abs(*this) == abs(b)
} // so sum must be zero)
return sum; // shallow swap on return
}
//: Multiplies this with a vnl_bignum
vnl_bignum& vnl_bignum::operator*= (const vnl_bignum& b)
{
// Infinity arithmetic:
assert (! b.is_infinity() || this->count != 0 ); // multiplication 0*Inf
assert (! this->is_infinity() || b.count != 0 ); // multiplication Inf*0
if (b.is_infinity()) return (*this) = (this->sign<0 ? -b : b);
if (this->is_infinity()) return (*this) = (b.sign<0 ? -(*this) : *this);
if (b.count == 0 || this->count == 0)
return (*this)=0L;
vnl_bignum prod;
prod.data = new Data[prod.count = this->count + b.count]; // allocate data for product
for (Counter i = 0; i < b.count; i++) // multiply each b "digit"
multiply_aux(*this, b.data[i], prod, i); // times b1 and add to total
prod.sign = this->sign * b.sign; // determine correct sign
prod.trim(); // trim excess data and ret.
return (*this)=prod;
}
//: Divides this by a vnl_bignum
vnl_bignum& vnl_bignum::operator/= (const vnl_bignum& b)
{
// Infinity arithmetic:
assert (! b.is_infinity() || ! this->is_infinity() ); // division Inf/Inf
if (b.is_infinity()) return (*this)=0L;
if (this->is_infinity()) return (*this) = (b.sign<0 ? -(*this) : *this);
assert (b.count!=0 || this->count != 0); // division 0/0
if (b.count == 0)
return (*this) = (this->sign < 0 ? vnl_bignum("-Inf") : vnl_bignum("+Inf"));
vnl_bignum quot, r; // Quotient and remainder
divide(*this,b,quot,r); // Call divide fn
return (*this) = quot;
}
//: Divides this by a vnl_bignum and replaces this by remainder.
vnl_bignum& vnl_bignum::operator%= (const vnl_bignum& b)
{
// Infinity arithmetic:
assert (! b.is_infinity() || ! this->is_infinity() ); // division Inf/Inf
if (b.is_infinity()) return *this; // remainder of x/Inf is x.
if (this->is_infinity()) return (*this) = 0L; // convention: remainder is 0
assert (b.count!=0 || this->count != 0); // division 0/0
if (b.count == 0) return (*this) = 0L; // convention: remainder is 0
vnl_bignum remain, q; // Quotient and remainder
divide(*this,b,q,remain); // divide by b and save remainder
return (*this) = remain; // shallow swap on return
}
//: Shifts bignum to the left l digits.
vnl_bignum vnl_bignum::operator<< (int l) const
{
// Infinity arithmetic:
if (this->is_infinity()) return *this;
if (l == 0 || *this == 0L) // if either arg is zero
return *this;
if (l < 0) // if shift amt is negative
return right_shift(*this,-l); // do an actual right shift
else // otherwise
return left_shift(*this,l); // do a left shift
}
//: Shifts bignum to the right l digits.
vnl_bignum vnl_bignum::operator>> (int l) const
{
// Infinity arithmetic:
if (this->is_infinity()) return *this;
if (l == 0 || *this == 0L) // if either arg is zero
return *this;
if (l < 0) // if shift amt is negative
return left_shift(*this,-l); // do an actual left shift
else // else
return right_shift(*this,l); // do a right shift
}
//: Two vnl_bignums are equal if and only if they have the same integer representation.
bool vnl_bignum::operator== (const vnl_bignum& rhs) const
{
if (this != &rhs) { // Check address
if (this->sign != rhs.sign) return false; // Different sign implies !=
if (this->count != rhs.count) return false; // Different size implies !=
for (Counter i = 0; i < this->count; i++) // Each data element the same?
if (this->data[i] != rhs.data[i]) return false; // No. Return !=
}
return true; // Yes. Return ==
}
//: Compares two vnl_bignums.
bool vnl_bignum::operator< (const vnl_bignum& rhs) const
{
if (this->sign < rhs.sign) return true; // Different signs?
if (this->sign > rhs.sign) return false;
if (this->sign == 1) // Both signs == 1
return magnitude_cmp(*this,rhs) < 0; // this must be smaller
else // Both signs == -1
return magnitude_cmp(*this,rhs) > 0; // this must be larger
}
//: Formatted output for bignum.
vcl_ostream& operator<< (vcl_ostream& os, const vnl_bignum& b)
{
vnl_bignum d = b; // Copy the input vnl_bignum
if (d.sign == -1) { // If it's negative
os << '-'; // Output leading minus sign
d.sign = 1; // Make d positive for divide
}
if (d.is_infinity()) return os<<"Inf";
vnl_bignum q,r; // Temp quotient and remainder
char *cbuf = new char[5 * (b.count+1)]; // Temp character buffer
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -