00001
00002 #include "vnl_decnum.h"
00003 #include <vcl_cassert.h>
00004 #include <vcl_sstream.h>
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 vnl_decnum::vnl_decnum(vcl_string const& r)
00016 : sign_('+'), data_(""), exp_(0L)
00017 {
00018 long exp = 0L;
00019 char const* p = r.c_str();
00020 while (*p == ' ' || *p == '\t' || *p == '\n' || *p == '\r') ++p;
00021 if (*p == '-') sign_ = '-', ++p;
00022 else if (*p == '+') ++p;
00023 if (*p == 'I' && *++p == 'n' && *++p == 'f') { data_ = "Inf"; }
00024 else if (*p == 'N' && *++p == 'a' && *++p == 'N') { data_ = "NaN"; }
00025 else {
00026 while (*p == '0') ++p;
00027 while (*p >= '0' && *p <= '9') data_.push_back(*p++);
00028 if (*p == '.') {
00029 ++p;
00030 while (*p >= '0' && *p <= '9') { data_.push_back(*p++); --exp; }
00031 }
00032 if (data_ == "") sign_ = ' ';
00033 else if (*p == 'e') {
00034 ++p;
00035 char sign = '+';
00036 if (*p == '-') sign = '-', ++p;
00037 else if (*p == '+') ++p;
00038 while (*p == '0') ++p;
00039 while (*p >= '0' && *p <= '9') exp_ *= 10L, exp_ += (*p-'0'), ++p;
00040 if (sign == '-') exp_ = -exp_;
00041 }
00042 exp_ += exp;
00043 if (sign_ == ' ') exp_ = 0L;
00044 }
00045 #ifdef DEBUG
00046 vcl_cerr << "Leaving vnl_decnum::vnl_decnum(\"" << r << "\") with " << sign_ << data_ << 'e' << exp_ << '\n';
00047 #endif
00048 }
00049
00050
00051 vnl_decnum::vnl_decnum(unsigned long r)
00052 : sign_('+'), data_(""), exp_(0L)
00053 {
00054 if (r == 0) sign_ = ' ';
00055 else {
00056 while (r) { data_.insert(data_.begin(), '0'+(r%10)); r/=10; }
00057 }
00058 }
00059
00060
00061 vnl_decnum::vnl_decnum(double r)
00062 {
00063 #ifdef DEBUG
00064 vcl_cerr << "vnl_decnum::vnl_decnum(double " << r << ")\n";
00065 #endif
00066 vcl_ostringstream os; os << r;
00067 *this = vnl_decnum(os.str());
00068 }
00069
00070
00071
00072 vnl_decnum::operator vcl_string() const
00073 {
00074 if (data_=="NaN") return "NaN";
00075 if (sign_==' ') return "0";
00076 vcl_string r=data_; if (sign_=='-') r.insert(r.begin(), sign_);
00077 if (exp_ == 0) return r;
00078
00079 r.push_back('e');
00080 long exp=exp_; if (exp < 0) { exp = -exp; r.push_back('-'); }
00081 vcl_string e="";
00082 while (exp) {e.insert(e.begin(), '0'+(exp%10)); exp /=10; }
00083 return r+e;
00084 }
00085
00086 vnl_decnum::operator unsigned long() const
00087 {
00088 if (data_ == "NaN") return 0L;
00089 if (data_ == "Inf") return 0xffffffffu;
00090 unsigned long l = 0L;
00091 for (long i=0; i<long(data_.length())+exp_; ++i) { l *= 10; if (i<long(data_.length())) l += (data_.c_str()[i]-'0'); }
00092 return l;
00093 }
00094
00095 vnl_decnum::operator long() const
00096 {
00097 if (data_ == "NaN") return 0L;
00098 if (data_ == "Inf" && sign_ == '+') return 0x7fffffff;
00099 else if (data_ == "Inf") return -0x7fffffff - 1;
00100 long l = 0L;
00101 for (long i=0; i<long(data_.length())+exp_; ++i) { l *= 10; if (i<long(data_.length())) l += (data_.c_str()[i]-'0'); }
00102 return sign_=='-' ? -l : l;
00103 }
00104
00105 vnl_decnum::operator unsigned int() const
00106 {
00107 if (data_ == "NaN") return 0L;
00108 if (data_ == "Inf") return 0xffffffffu;
00109 unsigned int l = 0;
00110 for (long i=0; i<long(data_.length())+exp_; ++i) { l *= 10; if (i<long(data_.length())) l += (data_.c_str()[i]-'0'); }
00111 return l;
00112 }
00113
00114 vnl_decnum::operator int() const
00115 {
00116 if (data_ == "NaN") return 0L;
00117 if (data_ == "Inf" && sign_ == '+') return 0x7fffffff;
00118 else if (data_ == "Inf") return -0x7fffffff - 1;
00119 int l = 0;
00120 for (long i=0; i<long(data_.length())+exp_; ++i) { l *= 10; if (i<long(data_.length())) l += (data_.c_str()[i]-'0'); }
00121 return sign_=='-' ? -l : l;
00122 }
00123
00124 bool vnl_decnum::operator==(vnl_decnum const& r) const
00125 {
00126
00127 if (sign_!=r.sign()) return false;
00128 else if (data_ == "NaN" || r.data() == "NaN") return false;
00129 else if (data_ == "Inf" && r.data() == "Inf") return true;
00130 else if (sign_ == ' ') return true;
00131 else if (exp_ == r.exp()) return data_==r.data();
00132 else if (exp_ > r.exp()) {
00133
00134
00135 return add_zeros(data_,exp_-r.exp()) == r.data();
00136 }
00137 else {
00138
00139 return add_zeros(r.data(),r.exp()-exp_) == data_;
00140 }
00141 }
00142
00143
00144
00145
00146 bool vnl_decnum::comp(vcl_string const& a, vcl_string const& b)
00147 {
00148 #ifdef DEBUG
00149 vcl_cerr << "Entering vnl_decnum::comp with " << a << " and " << b << '\n';
00150 #endif
00151 int i, na = int(a.length()), nb = int(b.length()), nc = na < nb ? na : nb;
00152 for (i = 0; i < nc; ++i) {
00153 if (a.c_str()[i] < b.c_str()[i]) return true;
00154 else if (a.c_str()[i] > b.c_str()[i]) return false;
00155 }
00156 for (; i < nb; ++i) {
00157 if ('0' < b.c_str()[i]) return true;
00158 }
00159 return false;
00160 }
00161
00162 bool vnl_decnum::operator< (vnl_decnum const& r) const
00163 {
00164 #ifdef DEBUG
00165 vcl_cerr << "Entering vnl_decnum::operator< with " << data_ << " and " << r.data() << '\n';
00166 #endif
00167 vcl_string rs = r.data();
00168 if (data_ == "NaN" || rs == "NaN") return false;
00169 else if (operator==(r)) return false;
00170 else if (data_ == "Inf") return sign_ == '-';
00171 else if (rs == "Inf") return r.sign() == '+';
00172
00173 if (sign_=='-' && r.sign() == '-') return -r < operator-();
00174 else if (sign_=='-') return true;
00175 else if (r.sign() == '-') return false;
00176 else if (sign_==' ') return true;
00177 else if (r.sign() == ' ') return false;
00178 else if (data_.length()+exp_ < rs.length()+r.exp()) return true;
00179 else if (data_.length()+exp_ > rs.length()+r.exp()) return false;
00180 else
00181 return comp(data_,rs);
00182 }
00183
00184
00185
00186
00187 vnl_decnum vnl_decnum::plus(vcl_string const& a, vcl_string const& b, long exp)
00188 {
00189 #ifdef DEBUG
00190 vcl_cerr << "Entering vnl_decnum::plus with " << a << " and " << b << '\n';
00191 #endif
00192 vcl_string result = "";
00193 int na=int(a.length()), nb=int(b.length()), carry=0;
00194 for (--na,--nb; na>=0&&nb>=0; --na,--nb) {
00195 char c = a.c_str()[na] + (b.c_str()[nb] - '0') + carry;
00196 if (c > '9') c-=10, carry=1; else carry=0;
00197 result.insert(result.begin(), c);
00198 }
00199 for (; na>=0&&nb<0; --na) {
00200 char c = a.c_str()[na] + carry;
00201 if (c > '9') c-=10, carry=1; else carry=0;
00202 result.insert(result.begin(), c);
00203 }
00204 for (; nb>=0&&na<0; --nb) {
00205 char c = b.c_str()[nb] + carry;
00206 if (c > '9') c-=10, carry=1; else carry=0;
00207 result.insert(result.begin(), c);
00208 }
00209 if (carry) result.insert(result.begin(), '1');
00210 return vnl_decnum('+',result,exp);
00211 }
00212
00213
00214
00215
00216
00217 vnl_decnum vnl_decnum::minus(vcl_string const& a, vcl_string const& b, long exp)
00218 {
00219 #ifdef DEBUG
00220 vcl_cerr << "Entering vnl_decnum::minus with " << a << " and " << b << '\n';
00221 #endif
00222 vcl_string result = "";
00223 int na=int(a.length()), nb=int(b.length()), carry=0;
00224 assert(na>=nb);
00225 for (--na,--nb; na>=0&&nb>=0; --na,--nb) {
00226 char c = a.c_str()[na] - (b.c_str()[nb] - '0') - carry;
00227 if (c < '0') c+=10, carry=1; else carry=0;
00228 result.insert(result.begin(), c);
00229 }
00230 for (; na>=0&&nb<0; --na) {
00231 char c = a.c_str()[na] - carry;
00232 if (c < '0') c+=10, carry=1; else carry=0;
00233 result.insert(result.begin(), c);
00234 }
00235 for (na=0; result.c_str()[na]=='0'; ++na) ;
00236 if (na) result.erase(0, na);
00237 assert(carry==0);
00238 return vnl_decnum('+',result,exp);
00239 }
00240
00241 vnl_decnum vnl_decnum::operator+(vnl_decnum const& r) const
00242 {
00243 #ifdef DEBUG
00244 vcl_cerr << "Entering vnl_decnum::operator+ with "
00245 << sign_ << data_ << 'e' << exp_ << " and "
00246 << r.sign() << r.data() << 'e' << r.exp() << '\n';
00247 #endif
00248 if (data_ == "NaN") return *this;
00249 else if (r.data() == "NaN") return r;
00250 else if (data_ == "Inf" && r.data() == "Inf") return sign_ == r.sign() ? *this : vnl_decnum("NaN");
00251 else if (data_ == "Inf") return *this;
00252 else if (r.data() == "Inf") return r;
00253
00254 if (sign_ == ' ') return r;
00255 else if (r.sign() == ' ') return *this;
00256 else if (operator==(-r)) return vnl_decnum(0L);
00257
00258 else if (exp_ < r.exp()) { return operator+(vnl_decnum(r.sign(), add_zeros(r.data(),r.exp()-exp_), exp_)); }
00259 else if (exp_ > r.exp()) { return r.operator+(*this); }
00260 else if (sign_ == '-' && r.sign() == '-') return - plus(data_, r.data(), exp_);
00261 else if (sign_ == '-' && operator<(-r)) return - minus(data_, r.data(), exp_);
00262 else if (sign_ == '-') return minus(r.data(), data_, exp_);
00263 else if (r.sign() == '-' && operator>(-r)) return minus(data_, r.data(), exp_);
00264 else if (r.sign() == '-') return - minus(r.data(), data_, exp_);
00265 else return plus(data_, r.data(), exp_);
00266 }
00267
00268
00269
00270
00271 vcl_string vnl_decnum::mult(vcl_string const& a, char b)
00272 {
00273 #ifdef DEBUG
00274 vcl_cerr << "Entering vnl_decnum::mult with " << a << " and " << b << '\n';
00275 #endif
00276 vcl_string result = "";
00277 int na=int(a.length()), carry=0, bb = b-'0';
00278 assert(bb >= 0 && bb <= 9);
00279 for (--na; na>=0; --na) {
00280 int c = (a.c_str()[na]-'0') * bb + carry;
00281 assert(c >= 0 && c <= 99);
00282 carry = c/10; c%=10;
00283 result.insert(result.begin(), '0'+c);
00284 }
00285 if (carry) result.insert(result.begin(), '0'+carry);
00286 return result;
00287 }
00288
00289 vnl_decnum vnl_decnum::operator*(vnl_decnum const& r) const
00290 {
00291 #ifdef DEBUG
00292 vcl_cerr << "Entering vnl_decnum::operator* with "
00293 << sign_ << data_ << 'e' << exp_ << " and "
00294 << r.sign() << r.data() << 'e' << r.exp() << '\n';
00295 #endif
00296 if (data_ == "NaN") return *this;
00297 else if (r.data() == "NaN") return r;
00298 else if (data_ == "Inf" || r.data() == "Inf")
00299 return sign_ == r.sign() ? vnl_decnum("+Inf")
00300 : (sign_==' ' || r.sign()==' ') ? vnl_decnum("NaN")
00301 : vnl_decnum("-Inf");
00302
00303 int sign = (sign_==' '?0:sign_=='-'?-1:1) * (r.sign()==' '?0:r.sign()=='-'?-1:1);
00304 vnl_decnum result(0L);
00305 if (sign == 0) return result;
00306 vcl_string zeros = "";
00307 int na=int(data_.length());
00308 for (--na; na>=0; --na) {
00309 result += vnl_decnum(mult(r.data(), data_.c_str()[na]) + zeros);
00310 zeros.push_back('0');
00311 }
00312 result <<= (exp_ + r.exp());
00313 return (sign==-1) ? -result : result;
00314 }
00315
00316
00317
00318
00319
00320
00321 vcl_string vnl_decnum::div(vcl_string const& a, vcl_string& b)
00322 {
00323 #ifdef DEBUG
00324 vcl_cerr << "Entering vnl_decnum::div with " << a << " and " << b << '\n';
00325 #endif
00326 int na=int(a.length()), nb=int(b.length());
00327 assert(na >= nb);
00328 if (comp(a,b)) ++nb;
00329 vcl_string u = "1";
00330 while (nb<na) { b.push_back('0'), u.push_back('0'); ++nb; }
00331 vcl_string c = b;
00332 for (; u[0]<'9'; u[0]++) {
00333 vnl_decnum d = plus(c,b,0L);
00334 if (vnl_decnum(a) < d) { b=c; return u; }
00335 c=d.data();
00336 }
00337
00338 b=c; return u;
00339 }
00340
00341 vnl_decnum vnl_decnum::operator/(vnl_decnum const& r) const
00342 {
00343 #ifdef DEBUG
00344 vcl_cerr << "Entering vnl_decnum::operator/ with "
00345 << sign_ << data_ << 'e' << exp_ << " and "
00346 << r.sign() << r.data() << 'e' << r.exp() << '\n';
00347 #endif
00348 if (data_ == "NaN") return *this;
00349 else if (r.data() == "NaN") return r;
00350 else if (data_ == "Inf" && r.data() == "Inf") return vnl_decnum("NaN");
00351 else if (r.data() == "Inf") return vnl_decnum(0L);
00352 else if (data_ == "Inf")
00353 return sign_ == r.sign() ? vnl_decnum("+Inf")
00354 : vnl_decnum("-Inf");
00355 else if (r == 0L)
00356 return sign_==' ' ? vnl_decnum("NaN")
00357 : sign_=='+' ? vnl_decnum("+Inf")
00358 : vnl_decnum("-Inf");
00359
00360 if (r == 1L) return *this;
00361 if (operator==(r)) return vnl_decnum('+',"1",0L);
00362 vcl_string a = data_, b = r.data();
00363 int na=int(a.length()), nb=int(b.length());
00364 vnl_decnum result(0L);
00365 while (na > nb || (na == nb && !comp(a,b))) {
00366 vcl_string c = b;
00367 vcl_string d = div(a, c);
00368 #ifdef DEBUG
00369 vcl_cerr << "vnl_decnum::div returns " << d << '\n';
00370 #endif
00371 result += vnl_decnum(d);
00372 vnl_decnum m = vnl_decnum(a) - vnl_decnum(c);
00373 a = m.data(); na=a.length();
00374 }
00375 result <<= (exp_ - r.exp());
00376 int sign = (sign_=='-'?-1:1) * (r.sign()=='-'?-1:1);
00377 return sign==-1 ? -result : result;
00378 }
00379
00380 vnl_decnum vnl_decnum::operator%(vnl_decnum const& r) const
00381 {
00382 #ifdef DEBUG
00383 vcl_cerr << "Entering vnl_decnum::operator% with "
00384 << sign_ << data_ << 'e' << exp_ << " and "
00385 << r.sign() << r.data() << 'e' << r.exp() << '\n';
00386 #endif
00387 if (r == 0L) return *this;
00388 else if (data_ == "NaN") return *this;
00389 else if (r.data() == "NaN") return r;
00390 else if (r.data() == "Inf") return vnl_decnum("NaN");
00391 else if (data_ == "Inf") return *this;
00392
00393 if (r == vnl_decnum("1")) return vnl_decnum("0");
00394 if (operator==(r)) return vnl_decnum("0");
00395 vcl_string a = data_, b = r.data();
00396 int na=int(a.length()), nb=int(b.length());
00397 while (na > nb || (na == nb && !comp(a,b))) {
00398 vcl_string c = b;
00399 vcl_string d = div(a, c);
00400 #ifdef DEBUG
00401 vcl_cerr << "vnl_decnum::div returns " << d << '\n';
00402 #endif
00403 vnl_decnum m = vnl_decnum(a) - vnl_decnum(c);
00404 a = m.data(); na=a.length();
00405 }
00406 if (na==0) return vnl_decnum(0L);
00407 else return vnl_decnum(sign_,a,exp_);
00408 }
00409
00410
00411 vcl_istream& operator>>(vcl_istream& s, vnl_decnum& r)
00412 {
00413 #ifdef DEBUG
00414 vcl_cerr << "Entering operator>>(istream,vnl_decnum) with " << r << '\n';
00415 #endif
00416 vcl_string data = "";
00417 int c = ' ';
00418 while (c == ' ' || c == '\t' || c == '\r') c=s.get();
00419 if (c == -1 || c == '\n') { r = vnl_decnum(0L); return s; }
00420 if (c == '-') { data = "-"; c=s.get(); }
00421 else if (c == '+') c=s.get();
00422 if (c == 'I' && s.get() == 'n' && s.get() == 'f') { data += "Inf"; }
00423 else if (c == 'N' && s.get() == 'a' && s.get() == 'N') { data = "NaN"; }
00424 else {
00425 while (c == '0') c=s.get();
00426 while ((c >= '0' && c <= '9') || c == '.') { data.push_back(c); c=s.get(); }
00427 if (c == 'e') {
00428 data.push_back(c); c=s.get();
00429 if (c == '-' || c == '+') { data.push_back(c); c=s.get(); }
00430 while (c >= '0' && c <= '9') { data.push_back(c); c=s.get(); }
00431 }
00432 }
00433 r = vnl_decnum(data);
00434 if (c > 0) s.putback(c);
00435 return s;
00436 }
00437
00438
00439
00440
00441 vnl_decnum& vnl_decnum::compactify()
00442 {
00443 if (sign_ == ' ' || data_ == "Inf") { exp_ = 0L; return *this; }
00444 unsigned long n = data_.find_last_not_of('0') + 1;
00445 unsigned long l = data_.length();
00446 if (n < l) {
00447 exp_ += l-n; data_.erase(n);
00448 }
00449 else if (n > l) {
00450 exp_ = 0; data_.clear(); sign_ = ' ';
00451 }
00452
00453 return *this;
00454 }