numerix_doc 0.4
|
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