numerix_doc 0.4
/Users/mourrain/Devel/mmx/numerix/src/string_scnot.cpp
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : string_scnot.cpp
00004 * DESCRIPTION: Scientific notation for intervals
00005 * COPYRIGHT  : (C) 2006  Joris van der Hoeven
00006 *******************************************************************************
00007 * This software falls under the GNU general public license and comes WITHOUT
00008 * ANY WARRANTY WHATSOEVER. See the file $TEXMACS_PATH/LICENSE for more details.
00009 * If you don't have this file, write to the Free Software Foundation, Inc.,
00010 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
00011 ******************************************************************************/
00012 
00013 #include <numerix/string_scnot.hpp>
00014 #include <numerix/floating.hpp>
00015 namespace mmx {
00016 
00017 static void
00018 decompose (const string& s, int& sign, string& mant, integer& expo) {
00019   // Sign
00020   if (N(s) > 0 && (s[0] == '+' || s[0] == '-')) {
00021     decompose (s (1, N(s)), sign, mant, expo);
00022     if (s[0] == '-') sign= -sign;
00023     return;
00024   }
00025 
00026   // Special values
00027   sign= 1; mant= ""; expo= 0;
00028   if (locase (s) == "nan") { mant= "NaN"; return; }
00029   if (locase (s) == "fuzz") { mant= "Fuzz"; return; }
00030   if (locase (s) == "infty") { mant= "Infty"; return; }
00031   if (locase (s) == "infinity") { mant= "Infty"; return; }
00032 
00033   // Get mantissa and decimal point
00034   int dot= -1;
00035   nat i= 0, n= N(s);
00036   while (i<n && (s[i] == '.' || (s[i] >= '0' && s[i] <= '9'))) {
00037     if (s[i] == '.') {
00038       if (dot != -1) { mant= "NaN"; return; }
00039       dot= i++;
00040     }
00041     else mant << s[i++];
00042   }
00043   if (dot == -1) dot= i;
00044 
00045   // Get exponent
00046   if (i<n && (s[i] == 'e' || s[i] == 'E')) {
00047     i++;
00048     int expo_sign= 1;
00049     while (i<n && (s[i] == '+' || s[i] == '-')) {
00050       if (s[i] == '-') expo_sign= -expo_sign;
00051       i++;
00052     }
00053     while (i<n && s[i] >= '0' && s[i] <= '9') {
00054       expo= 10*expo + ((int) (s[i] - '0'));
00055       i++;
00056     }
00057     expo= expo_sign * expo;
00058   }
00059 
00060   // Finish
00061   if (i != n) { mant= "NaN"; return; }
00062   if (mant == "") { mant= "0"; dot++; }
00063   expo += (dot - 1);
00064   while (N(mant) > 1 && mant[0] == '0') {
00065     mant= mant (1, N(mant));
00066     expo= expo - 1;
00067   }
00068   if (s == "0") sign= 0;
00069 }
00070 
00071 static string
00072 recompose (int sign, const string& mant, const integer& i) {
00073   if (sign == 0) return "0";
00074   if (locase (mant) == "nan") return "NaN";
00075   if (mant == "0") return "0e" * as_string (i);
00076   if (sign < 0) return "-" * recompose (1, mant, i);
00077   if (locase (mant) == "infty") return "Infty";
00078   if (i == -1) return "0." * mant;
00079   if (i == -2) return "0.0" * mant;
00080   if (i == -3) return "0.00" * mant;
00081   if (N(mant) == 1) return mant * "e" * as_string (i);
00082   if (i >= 0 && i<6 && N(mant)>i+1)
00083     return mant (0, as_int (i)+1) * "." * mant (as_int (i)+1, N(mant));
00084   return mant (0, 1) * "." * mant (1, N(mant)) * "e" * as_string (i);
00085 }
00086 
00087 static void
00088 inc_mantissa (string& mant, integer& expo) {
00089   string mant2= as_string (integer (mant) + 1);
00090   if (N (mant2) > N (mant)) expo= expo + 1;
00091   mant= mant2;
00092 }
00093 
00094 static string
00095 make_range (string& mant1, integer& expo1,
00096             string& mant2, integer& expo2)
00097 {
00098   if (expo2 == expo1 + 1) {
00099     mant1= "0" * mant1;
00100     expo1= expo1 + 1;
00101   }
00102   if (expo2 != expo1) return "0e" * as_string (expo2 + 1);
00103 
00104   nat i, n= min (N(mant1), N(mant2));
00105   for (i=0; i<n; i++)
00106     if (mant1[i] != mant2[i]) {
00107       if (mant2[i] == mant1[i] + 1) {
00108         i++;
00109         while (i<n && (mant1[i] == '9' && mant2[i] == '0')) i++;
00110         if (i >= n ||
00111             (mant1[i] >= '0' && mant1[i] <= '4') ||
00112             (mant2[i] >= '5' && mant2[i] <= '9')) i--;
00113       }
00114       break;
00115     }
00116   string mant2b= mant2 (0, i);
00117   if (i>0 && mant1[i-1] == mant2[i-1]) {
00118     if (i<N(mant1) && mant1[i] >= '5')
00119       inc_mantissa (mant2b, expo2);
00120     else if (i<N(mant2) && mant2[i] >= '5') {
00121       bool inc= (i != 0 && mant2[i-1] >= '5');
00122       mant2b= mant2b (0, N(mant2b) - 1);
00123       if (inc) inc_mantissa (mant2b, expo2);
00124     }
00125   }
00126   if (mant2b == "") return "0e" * as_string (expo2 + 1);
00127   else return recompose (1, mant2b, expo2);
00128 }
00129 
00130 string
00131 make_range (const string& s1, const string& s2) {
00132   int     sign1, sign2;
00133   string  mant1, mant2;
00134   integer expo1, expo2;
00135   decompose (s1, sign1, mant1, expo1);
00136   decompose (s2, sign2, mant2, expo2);
00137   if (locase (mant1) == "nan" || locase (mant2) == "nan") return "NaN";
00138   if (locase (mant1) == "infty" || locase (mant2) == "infty") {
00139     if (mant1 == mant2 && sign1 == sign2)
00140       return recompose (sign1, mant1, expo1);
00141     return "Fuzz";
00142   }
00143   if (sign1 != sign2) {
00144     integer expo= expo1;
00145     if (sign1 == 0 || (sign2 != 0 && expo2 > expo1)) expo= expo2;
00146     return "0e" * as_string (expo+1);
00147   }
00148   if (sign1 == 0) return "0";
00149   if (sign1 < 0) return "-" * make_range (mant2, expo2, mant1, expo1);
00150   else return make_range (mant1, expo1, mant2, expo2);
00151 }
00152 
00153 void
00154 decompose_range (const string& s, string& l, string& r) {
00155   int     sign;
00156   string  mant;
00157   integer expo;
00158   decompose (s, sign, mant, expo);
00159   if (locase (mant) == "fuzz") { l= "-Infty"; r= "Infty"; return; }
00160   if (locase (mant) == "nan") { l= "NaN"; r= "NaN"; return; }
00161   if (locase (mant) == "infty") { l= r= recompose (sign, mant, 0); return; }
00162   if (sign == 0) { l= r= "0"; }
00163   if (mant == "0") {
00164     l= recompose (-1, "1", expo);
00165     r= recompose (1, "1", expo);
00166   }
00167   else {
00168     string mant1= as_string (integer (mant) - 1) * "5";
00169     string mant2= mant * "5";
00170     l= recompose (sign, sign>0? mant1: mant2, expo);
00171     r= recompose (sign, sign>0? mant2: mant1, expo);
00172   }
00173 }
00174 
00175 string
00176 trunc_digits (const string& s, xnat dd) {
00177   if (mmx_significant_digits != 0) {
00178     if (dd == 0) dd= mmx_significant_digits;
00179     else dd= min (dd, mmx_significant_digits);
00180   }
00181   if (locase (s) == "nan") return "NaN";
00182   if (locase (s) == "infty") return "Infty";
00183   if (locase (s) == "-infty") return "-Infty";
00184   if (locase (s) == "fuzz") return "Fuzz";
00185   int     sign;
00186   string  mant;
00187   integer expo;
00188   decompose (s, sign, mant, expo);
00189   if (dd == 0 || N(mant) <= dd) return recompose (sign, mant, expo);
00190   string mant2= mant (0, dd);
00191   if (mant[dd] >= '5') inc_mantissa (mant2, expo);
00192   return recompose (sign, mant2, expo);
00193 }
00194 
00195 static bool
00196 is_integer (const string& s) {
00197   nat i= 0;
00198   if (i<N(s) && s[i] == '-') i++;
00199   for (; i<N(s); i++)
00200     if (s[i] < '0' || s[i] > '9') return false;
00201   return true;
00202 }
00203 
00204 syntactic
00205 flatten_number (const string& s) {
00206   if (N(s) == 0) return 0;
00207   if (s[0] == '-') return -flatten_number (s (1, N(s)));
00208   if (!mmx_pretty_exponents) return syntactic (s);
00209   nat i;
00210   for (i=N(s)-1; i!=0; i--)
00211     if (s[i] == 'e') break;
00212   if (i > 0 && is_integer (s (i+1, N(s))))
00213     return syntactic (s (0, i)) *
00214            pow (syntactic (10), syntactic (s (i+1, N(s))));
00215   return syntactic (s);
00216 }
00217 
00218 } // namespace mmx
 All Classes Namespaces Files Functions Variables Typedefs Friends Defines