Main Page | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Class Members | File Members | Related Pages

Value.cpp

Go to the documentation of this file.
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 


Documentation generated with Doxygen on Sun Feb 6 17:10:49 2005
Visit MathStudio home page for more info

[ Top ]