00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
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
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
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
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
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
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 }