00001 00002 // MathCore = a WYSIWYG equation editor + a powerful math engine // 00003 // Copyright (C) 2003 by Francesco Montorsi // 00004 // // 00005 // This library is free software; you can redistribute it and/or // 00006 // modify it under the terms of the GNU Lesser General Public // 00007 // License as published by the Free Software Foundation; either // 00008 // version 2.1 of the License, or (at your option) any later // 00009 // version. // 00010 // // 00011 // This library is distributed in the hope that it will be useful, // 00012 // but WITHOUT ANY WARRANTY; without even the implied warranty of // 00013 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // 00014 // GNU Lesser General Public License for more details. // 00015 // // 00016 // You should have received a copy of the GNU Lesser General Public // 00017 // License along with this program; if not, write to the Free // 00018 // Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, // 00019 // MA 02111-1307, USA. // 00020 // // 00021 // For any comment, suggestion or feature request, please contact // 00022 // the administrator of the project at frm@users.sourceforge.net // 00023 // // 00030 00031 00032 00033 // optimization for GCC compiler 00034 #ifdef __GNUG__ 00035 #pragma implementation "Value.h" 00036 #endif 00037 00038 // includes 00039 #include "mc/mcprec.h" 00040 #ifdef __BORLANDC__ 00041 #pragma hdrstop 00042 #endif 00043 00044 #ifndef mcPRECOMP 00045 #include <wx/string.h> 00046 00047 #include "mc/MathUtils.h" 00048 #include "mc/Value.h" 00049 #endif 00050 00051 00052 // setup STATIC 00053 int mcValue::m_nMaxValueSharing = -1; 00054 00055 mcIntegerValue *mcIntegerValue::pOne = NULL; 00056 mcIntegerValue *mcIntegerValue::pZero = NULL; 00057 mcIntegerValue *mcIntegerValue::pNAN = NULL; 00058 mcIntegerValue *mcIntegerValue::pPosInf = NULL; 00059 mcIntegerValue *mcIntegerValue::pNegInf = NULL; 00060 00061 mcRealValue *mcRealValue::pOne = NULL; 00062 mcRealValue *mcRealValue::pZero = NULL; 00063 mcRealValue *mcRealValue::pNAN = NULL; 00064 mcRealValue *mcRealValue::pPosInf = NULL; 00065 mcRealValue *mcRealValue::pNegInf = NULL; 00066 00067 00068 00069 00070 00071 00072 // ----------------------------------------------- 00073 // GMP alloc/free functions provided by MathCore 00074 // ----------------------------------------------- 00075 00076 void *mcGMPAlloc(size_t n) { return new char[n]; } 00077 void mcGMPFree(void *mem, size_t) { delete [] ((char *)mem); } 00078 00079 void *mcGMPRealloc(void *mem, size_t oldsize, size_t newsize) 00080 { 00081 void *newp = mcGMPAlloc(newsize); 00082 00083 // copy from old to new and destroy old 00084 memcpy(newp, mem, mcMIN(oldsize, newsize)); 00085 mcGMPFree(mem, oldsize); 00086 00087 return newp; 00088 } 00089 00090 00091 00092 00093 // -------------- 00094 // mcVALUE 00095 // -------------- 00096 00097 void mcValue::Init() // this one is static 00098 { 00099 // install our alloc/free functions 00100 mp_set_memory_functions(mcGMPAlloc, mcGMPRealloc, mcGMPFree); 00101 00102 // init STATICS 00103 mcIntegerValue::pNAN = new mcIntegerValue(); 00104 mcIntegerValue::pNAN->math_AddFlag(mcVALUE_NAN_FLAG); 00105 mcIntegerValue::pPosInf = new mcIntegerValue(); 00106 mcIntegerValue::pPosInf->math_AddFlag(mcVALUE_POSINF_FLAG); 00107 mcIntegerValue::pNegInf = new mcIntegerValue(); 00108 mcIntegerValue::pNegInf->math_AddFlag(mcVALUE_NEGINF_FLAG); 00109 00110 mcIntegerValue::pZero = new mcIntegerValue(0); 00111 mcIntegerValue::pOne = new mcIntegerValue(1); 00112 00113 00114 mcRealValue::pNAN = new mcRealValue(*mcIntegerValue::pNAN); 00115 mcRealValue::pPosInf = new mcRealValue(*mcIntegerValue::pPosInf); 00116 mcRealValue::pNegInf = new mcRealValue(*mcIntegerValue::pNegInf); 00117 mcRealValue::pZero = new mcRealValue(0.0); 00118 mcRealValue::pOne = new mcRealValue(1.0); 00119 } 00120 00121 void mcValue::Cleanup() // this one is static 00122 { 00123 // delete STATICs 00124 delete mcIntegerValue::pZero; 00125 delete mcIntegerValue::pOne; 00126 delete mcIntegerValue::pNAN; 00127 delete mcIntegerValue::pPosInf; 00128 delete mcIntegerValue::pNegInf; 00129 00130 delete mcRealValue::pZero; 00131 delete mcRealValue::pOne; 00132 delete mcRealValue::pNAN; 00133 delete mcRealValue::pPosInf; 00134 delete mcRealValue::pNegInf; 00135 } 00136 00137 00138 00139 00140 00141 // ---------------- 00142 // mcINTEGERVALUE 00143 // ---------------- 00144 00145 mcIntegerValue::mcIntegerValue(const mcRationalValue &m) 00146 { InternalInit(m.GetFlags()); mpz_set_q(MP(), m.cMP()); } 00147 00148 mcIntegerValue::mcIntegerValue(const mcRealValue &m) 00149 { InternalInit(m.GetFlags()); mpz_set_f(MP(), m.cMP()); } 00150 00151 wxString mcIntegerValue::GetStr() const 00152 { 00153 // conversion GMP -> string 00154 char *buf = new char[mpz_sizeinbase(cMP(), 10)+5]; 00155 mpz_get_str(buf, 10, cMP()); 00156 wxString str(GMP2WX(buf)); 00157 delete [] buf; 00158 00159 // when this is a null value, GMP does not return anything... 00160 if (str.IsEmpty()) str = wxT("0"); 00161 00162 return str; 00163 } 00164 00165 00166 00167 00168 // ---------------- 00169 // mcRATIONALVALUE 00170 // ---------------- 00171 00172 mcRationalValue::mcRationalValue(const mcIntegerValue &m) 00173 { InternalInit(m.GetFlags()); mpq_set_z(MP(), m.cMP()); } 00174 00175 mcRationalValue::mcRationalValue(const mcRealValue &m) 00176 { InternalInit(m.GetFlags()); mpq_set_f(MP(), m.cMP()); } 00177 00178 mcRationalValue::mcRationalValue(const mcIntegerValue &num, const mcIntegerValue &den) 00179 { InternalInit(); mpq_set_si(MP(), num.GetLong(), den.GetLong()); } 00180 00181 wxString mcRationalValue::GetStr() const 00182 { 00183 // conversion GMP . string 00184 //wxString str; 00185 00186 // in this way we would get something like: num/den 00187 /*int n = mpz_sizeinbase (mpq_numref(cMP()), 10) 00188 + mpz_sizeinbase (mpq_denref(cMP()), 10) + 3; 00189 mpq_get_str(str.GetWriteBuf(n), 10, cMP());*/ 00190 00191 // convert us to a mcRealValue... 00192 mcRealValue r(*this); 00193 return r.GetStr(); 00194 /* 00195 str.UngetWriteBuf(); 00196 return str;*/ 00197 } 00198 00199 int mcRationalValue::GetFractionalDigitCount(int max) const 00200 { 00201 mcRealValue n = *this; 00202 int count = 0; 00203 00204 // just multiply by 10 the number until we get an integer... 00205 while (!n.isInteger()) { 00206 00207 // avoid problems with numbers with infinite fractional digits... 00208 if (count == max) 00209 break; 00210 00211 n *= 10.0; 00212 count++; 00213 } 00214 00215 // check if we still have fractional digits in "n" 00216 if (!n.isInteger()) 00217 return -1; // more than "max" digits 00218 00219 return count; 00220 } 00221 00222 mcIntegerValue mcRationalValue::MakeInteger(int max) const 00223 { 00224 int count = GetFractionalDigitCount(max); 00225 mcRealValue n(*this); 00226 00227 if (count > 0) { 00228 00229 // if the given number has a valid number of fractional digits, 00230 // we can make it integer without problems... 00231 //mcRealValue multiplier(10);, count); 00232 mcRealValue res = n * mcRealValue(10).pow(count); 00233 mcASSERT(res.isInteger(), wxT("Something wrong in the algorithm")); 00234 00235 return mcIntegerValue(res); 00236 00237 } else if (count == 0) { 00238 00239 // the given number should be an integer stored in a double... 00240 mcASSERT(isInteger(), wxT("Fractional digit count should not be zero then !!!")); 00241 return *this; 00242 } 00243 00244 // count is less than zero; 00245 // the given number has more fractional digits than "max"; approx 00246 // it anyway... 00247 mcRealValue res = n * mcRealValue(10).pow(max); 00248 return mcIntegerValue(res.floor()); 00249 } 00250 00251 00252 00253 00254 // ---------------- 00255 // mcREALVALUE 00256 // ---------------- 00257 00258 wxString mcRealValue::GetBaseStr(int *p, int digits, int *n) const 00259 { 00260 // conversion GMP -> string 00261 mp_exp_t exp; 00262 char *buf = new char[digits+5]; 00263 mpf_get_str(buf, &exp, 10, digits, cMP()); 00264 wxString str(GMP2WX(buf)); 00265 delete [] buf; 00266 00267 // when this is a null value, GMP does not return anything... 00268 if (str.IsEmpty()) { str = wxT("0"); exp=1; } 00269 if (p) *p = (int)exp; 00270 if (n) *n = exp - str.Len() + (str.GetChar(0) == wxT('-') ? 1 : 0); 00271 00272 return str; 00273 } 00274 00275 wxString mcRealValue::GetStr(int digits) const 00276 { 00277 int exp, n; 00278 wxString str = GetBaseStr(&exp, digits, &n); 00279 00280 // Since in the string returned by GMP a dot is implicit before 00281 // the first digit, numbers are returned in the format: 00282 // 00283 // 5 . 0.5*10^1 (str = 5, exp = 1) 00284 // 43 . 0.43*10^2 (str = 43, exp = 2) 00285 // 00286 // and for numbers with trailing zeros: 00287 // 00288 // 1000 . 0.1*10^4 (str = 1, exp = 4) 00289 // 45000 . 0.45*10^5 (str = 45, exp = 5) 00290 // 00291 // So, to make the string clearer, we will append E followed by the 00292 // exponent only for those numbers whose str's lenght does not coincide 00293 // the exponent... 00294 if (n > 0) str += wxString::Format(wxT("E%d"), exp-1); 00295 00296 return str; 00297 } 00298 00299 wxString mcRealValue::GetSmartStr(int threshold, int digits) const 00300 { 00301 int exp, n; 00302 wxString str = GetBaseStr(&exp, digits, &n); 00303 00304 // see the comments in #GetStr 00305 if (n < 0) { 00306 // we need a decimal point 00307 wxString left = str.Left(exp); 00308 if (left.IsEmpty()) left = wxT("0"); 00309 00310 str = left + wxT(".") + str.Right(-n); 00311 00312 } else if (n == 0) { 00313 00314 // the string is already okay 00315 return str; 00316 00317 } else { 00318 00319 if (n < threshold) // exp is small enough ? 00320 str += wxString(wxT('0'), n); // like in GetExtStr 00321 else 00322 str += wxString::Format(wxT("E%d"), exp-1); // like in GetStr 00323 } 00324 00325 return str; 00326 } 00327 00328 wxString mcRealValue::GetExtStr(int digits) const 00329 { 00330 int exp, n; 00331 wxString str = GetBaseStr(&exp, digits, &n); 00332 00333 // unroll all the exponent digits... see #GetStr 00334 if (n > 0) str += wxString(wxT('0'), n); 00335 00336 return str; 00337 } 00338 00339 mcRealValue mcRealValue::GetFromDigitRange(int begin, int end, int digits) const 00340 { 00341 wxString str = GetSmartStr(digits); 00342 00343 // if not specified, the end is the last digit 00344 if (end == -1) end = str.Len(); 00345 00346 // extract the string from the number string 00347 str = str.Mid(begin, end-begin); 00348 00349 return mcRealValue(str); 00350 } 00351 00352 int mcRealValue::GetNumOfDigits(int digits) const 00353 { 00354 // just use this simple function 00355 wxString tmp = GetSmartStr(digits); 00356 return tmp.Len(); // num of digits = lenght of the string 00357 } 00358 00359 mcRealValue mcRealValue::InsertDigit(wxChar digittoadd, int pos, int digits) const 00360 { 00361 // add a digit using strings 00362 wxString str = GetSmartStr(digits); 00363 00364 // if this is the string expression of this number: 00365 // 00366 // ABCD|EF where | is the "digits" variable (= 4 in this case) 00367 // #digit 0123445 00368 // 00369 if (pos == -1) pos = str.Len(); 00370 str = str.Left(pos) + digittoadd + str.Right(str.Len()-pos); 00371 00372 // reconvert the string to a number 00373 return mcRealValue(str); 00374 } 00375 00376 mcRealValue mcRealValue::DeleteDigit(int n, int digits) const 00377 { 00378 wxString str = GetSmartStr(digits); 00379 mcASSERT(n > 0, wxT("The digit to delete must not be zero-based")); 00380 00381 // remove the n-th digit 00382 str.Remove(n-1, 1); 00383 00384 // reconvert the string to a number 00385 return mcRealValue(str); 00386 } 00387 /* 00388 bool mcRealValue::isInteger() const 00389 { 00390 unsigned long f = floor(); 00391 unsigned long c = ceil(); 00392 unsigned long t = trunc(); 00393 return (f == c) && (c == t); 00394 } 00395 */ 00396 00397 00398 00399
[ Top ] |