2004-04-24 Andreas Nahr <ClassDevelopment@A-SoftTech.com>
[mono.git] / mcs / class / corlib / System / FloatingPointFormatter.cs
1 //
2 // System.FloatingPointFormatter.cs
3 //
4 // Author:
5 //   Pedro Martinez Juliá <yoros@wanadoo.es>
6 //
7 // Copyright (C) 2003 Pedro Martíez Juliá <yoros@wanadoo.es>
8 //
9
10 using System;
11 using System.Text;
12 using System.Collections;
13 using System.Globalization;
14
15
16 namespace System {
17
18         internal class FloatingPointFormatter {
19
20                 struct Format {
21                         public double p;
22                         public double p10;
23                         public int dec_len;
24                         public int dec_len_min;
25                 }
26                 
27                 Format format1;
28                 Format format2;
29
30                 public FloatingPointFormatter
31                         (double p, double p10, int dec_len, int dec_len_min,
32                          double p2, double p102, int dec_len2, int dec_len_min2) {
33                          
34                         format1.p = p;
35                         format1.p10 = p10;
36                         format1.dec_len = dec_len;
37                         format1.dec_len_min = dec_len_min;
38                         
39                         format2.p = p2;
40                         format2.p10 = p102;
41                         format2.dec_len = dec_len2;
42                         format2.dec_len_min = dec_len_min2;
43                 }
44
45                 public string GetStringFrom
46                                 (string format, NumberFormatInfo nfi, double value) {
47                                 
48                         if (format == null || format == "") {
49                                 format = "G";
50                         }
51                         if (nfi == null) {
52                                 nfi = NumberFormatInfo.CurrentInfo;
53                         }
54                         if (Double.IsNaN(value)) {
55                                 return nfi.NaNSymbol;
56                         }
57                         if (Double.IsNegativeInfinity(value)) {
58                                 return nfi.NegativeInfinitySymbol;
59                         }
60                         if (Double.IsPositiveInfinity(value)) {
61                                 return nfi.PositiveInfinitySymbol;
62                         }
63                         
64                         char specifier;
65                         int precision;
66                         if (!ParseFormat(format, out specifier, out precision)) {
67                                 try {
68                                         return FormatCustom (format1, value, nfi, format);
69                                 }
70                                 catch (Exception) {
71                                         string msg = "An exception was thrown but the " +
72                                                 "application will continue working right.\n" +
73                                                 "Please mail to \"yoros@wanadoo.es\" with the " +
74                                                 "subject \"FORMAT_EXCEPTION\" and the content: " +
75                                                 "Format: ->" + format + "<-; Value: ->" + value +
76                                                 "<-;\n";
77                                         Console.Error.Write (msg); 
78                                         return FormatGeneral (format1, value, nfi, -1);
79                                 }
80                         }
81                         
82                         Format formatData = format1;//(precision > format1.dec_len+1) ? format2 : format1;
83                         
84                         switch (specifier) {
85                         case 'C':
86                                 return FormatCurrency (formatData, value, nfi, precision);
87                         case 'D':
88                                 throw new FormatException(Locale.GetText(
89                                         "The specified format is invalid") + ": " + format);
90                         case 'E':
91                                 formatData = (precision > format1.dec_len) ? format2 : format1;
92                                 return FormatExponential (formatData, value, nfi, precision, format[0]);
93                         case 'F':
94                                 return FormatFixedPoint (formatData, value, nfi, precision);
95                         case 'G':
96                                 return FormatGeneral (formatData, value, nfi, precision);
97                         case 'N':
98                                 return FormatNumber (formatData, value, nfi, precision);
99                         case 'P':
100                                 return FormatPercent (formatData, value, nfi, precision);
101                         case 'R':
102                                 return FormatReversible (formatData, value, nfi, precision);
103                         case 'X':
104                                 throw new FormatException(Locale.GetText(
105                                         "The specified format is invalid") + ": " + format);
106                         default:
107                                 throw new FormatException(Locale.GetText(
108                                         "The specified format is invalid") + ": " + format);
109                         }
110                 }
111
112                 private bool ParseFormat (string format,
113                                 out char specifier, out int precision) {
114                         specifier = '\0';
115                         precision = format2.dec_len;
116                         
117                         // FIXME: Math.Round is used and the max is 15.
118                         
119                         if (precision > 15)
120                                 precision = 15;
121                                 
122                         switch (format.Length) {
123                         case 1:
124                                 specifier = Char.ToUpper(format[0]);
125                                 precision = -1;
126                                 return true;
127                         case 2:
128                                 if (Char.IsLetter(format[0]) && Char.IsDigit(format[1])) {
129                                         specifier = Char.ToUpper(format[0]);
130                                         precision = Convert.ToInt32(format[1] - '0');
131                                         return true;
132                                 }
133                                 break;
134                         case 3:
135                                 if (Char.IsLetter(format[0]) && Char.IsDigit(format[1])
136                                                 && Char.IsDigit(format[2])) {
137                                         specifier = Char.ToUpper(format[0]);
138                                         precision = Convert.ToInt32(format.Substring(1, 2));
139                                         return true;
140                                 }
141                                 break;
142                         }
143                         return false;
144                 }
145
146                 private void Normalize (Format formatData, double value, int precision,
147                                 out long mantissa, out int exponent) {
148                         mantissa = 0;
149                         exponent = 0;
150                         if (value == 0.0 ||
151                                 Double.IsInfinity(value) ||
152                                 Double.IsNaN(value)) {
153                                 return;
154                         }
155                         value = Math.Abs(value);
156                         if (precision <= (formatData.dec_len) && precision >= 0) {
157                                 value = Math.Round (value, precision);
158                         }
159                         
160                         if (value == 0.0 ||
161                                 Double.IsInfinity(value) ||
162                                 Double.IsNaN(value)) {
163                                 return;
164                         }
165                         
166                         if (value >= formatData.p10) {
167                                 while (value >= formatData.p10) {
168                                         value /= 10;
169                                         exponent++;
170                                 }
171                         }
172                         else if (value < formatData.p) {
173                                 while (value < formatData.p) {
174                                         value *= 10;
175                                         exponent--;
176                                 }
177                         }
178                         mantissa = (long) Math.Round(value);
179                 }
180
181                 private string FormatCurrency (Format formatData, double value,
182                                 NumberFormatInfo nfi, int precision) {
183                                 
184                         precision = (precision >= 0) ? precision : nfi.CurrencyDecimalDigits;
185                         string numb = FormatNumberInternal (formatData, value, nfi, precision);
186                         if (value < 0) {
187                                 switch (nfi.CurrencyNegativePattern) {
188                                 case 0:
189                                         return "(" + nfi.CurrencySymbol + numb + ")";
190                                 case 1:
191                                         return nfi.NegativeSign + nfi.CurrencySymbol + numb;
192                                 case 2:
193                                         return nfi.CurrencySymbol + nfi.NegativeSign + numb;
194                                 case 3:
195                                         return nfi.CurrencySymbol + numb + nfi.NegativeSign;
196                                 case 4:
197                                         return "(" + numb + nfi.CurrencySymbol + ")";
198                                 case 5:
199                                         return nfi.NegativeSign + numb + nfi.CurrencySymbol;
200                                 case 6:
201                                         return numb + nfi.NegativeSign + nfi.CurrencySymbol;
202                                 case 7:
203                                         return numb + nfi.CurrencySymbol + nfi.NegativeSign;
204                                 case 8:
205                                         return nfi.NegativeSign + numb + " " + nfi.CurrencySymbol;
206                                 case 9:
207                                         return nfi.NegativeSign + nfi.CurrencySymbol + " " + numb;
208                                 case 10:
209                                         return numb + " " + nfi.CurrencySymbol + nfi.NegativeSign;
210                                 case 11:
211                                         return nfi.CurrencySymbol + " " + numb + nfi.NegativeSign;
212                                 case 12:
213                                         return nfi.CurrencySymbol + " " + nfi.NegativeSign + numb;
214                                 case 13:
215                                         return numb + nfi.NegativeSign + " " + nfi.CurrencySymbol;
216                                 case 14:
217                                         return "(" + nfi.CurrencySymbol + " " + numb + ")";
218                                 case 15:
219                                         return "(" + numb + " " + nfi.CurrencySymbol + ")";
220                                 default:
221                                         throw new ArgumentException(Locale.GetText(
222                                                 "Invalid CurrencyNegativePattern"));
223                                 }
224                         }
225                         else {
226                                 switch (nfi.CurrencyPositivePattern) {
227                                 case 0:
228                                         return nfi.CurrencySymbol + numb ;
229                                 case 1:
230                                         return numb + nfi.CurrencySymbol;
231                                 case 2:
232                                         return nfi.CurrencySymbol + " " + numb;
233                                 case 3:
234                                         return numb + " " + nfi.CurrencySymbol;
235                                 default:
236                                         throw new ArgumentException(Locale.GetText(
237                                                 "invalid CurrencyPositivePattern"));
238                                 }
239                         }
240                 }
241
242                 private string FormatExponential (Format formatData, double value, NumberFormatInfo nfi,
243                                 int precision, char exp_char) {
244                         StringBuilder sb = new StringBuilder();
245                         precision = (precision >= 0) ? precision : 6;
246                         int decimals = precision;
247                         long mantissa;
248                         int exponent;
249                         Normalize (formatData, value, precision, out mantissa, out exponent);
250                         if (formatData.dec_len > precision) {
251                                 double aux = mantissa;
252                                 for (int i = 0; i < formatData.dec_len - precision; i++) {
253                                         aux /= 10;
254                                 }
255                                 mantissa = (long) Math.Round(aux);
256                                 for (int i = 0; i < formatData.dec_len - precision; i++) {
257                                         mantissa *= 10;
258                                 }
259                         }
260                         bool not_null = false;
261                         if (mantissa != 0.0) {
262                                 for (int i = 0; i < formatData.dec_len || mantissa >= 10; i++) {
263                                         if ((not_null == false) && ((mantissa % 10) != 0)) {
264                                                 not_null = true;
265                                         }
266                                         if (not_null) {
267                                                 sb.Insert(0, (char)('0' + (mantissa % 10)));
268                                                 precision--;
269                                         }
270                                         mantissa /= 10;
271                                         exponent++;
272                                 }
273                         }
274                         if (decimals == 0) {
275                                 sb = new StringBuilder();
276                                 sb.Append((char)('0' + (mantissa % 10)));
277                         }
278                         else {
279                                 while (precision > 0) {
280                                         sb.Append('0');
281                                         precision--;
282                                 }
283                                 if (sb.Length == 0) {
284                                         sb.Insert(0, "0");
285                                 }
286                                 sb.Insert (0, (char)('0' + (mantissa % 10)) +
287                                                 nfi.NumberDecimalSeparator);
288                         }
289                         if (exponent >= 0) {
290                                 sb.Append(exp_char + nfi.PositiveSign);
291                         }
292                         else {
293                                 sb.Append(exp_char + nfi.NegativeSign);
294                         }
295                         sb.Append(Math.Abs(exponent).ToString("000"));
296                         if (value < 0.0) {
297                                 sb.Insert(0, nfi.NegativeSign);
298                         }
299                         return sb.ToString();
300                 }
301
302                 private string FormatFixedPoint (Format formatData, double value,
303                                 NumberFormatInfo nfi, int precision) {
304                         StringBuilder sb = new StringBuilder();
305                         precision = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
306                         int decimals = precision;
307                         long mantissa;
308                         int exponent;
309                         Normalize (formatData, value, precision, out mantissa, out exponent);
310                         if (exponent >= 0) {
311                                 while (decimals > 0) {
312                                         sb.Append("0");
313                                         decimals--;
314                                 }
315                         }
316                         else {
317                                 int decimal_limit = -(decimals + 1);
318                                 while (exponent < 0) {
319                                         if (exponent > decimal_limit) {
320                                                 sb.Insert(0, (char)('0' + (mantissa % 10)));
321                                         }
322                                         mantissa /= 10;
323                                         exponent++;
324                                         decimals--;
325                                 }
326                                 if (decimals > 0) {
327                                         sb.Append ('0', decimals);
328                                         decimals = 0;
329                                 }
330                         }
331                         if (precision != 0) {
332                                 sb.Insert(0, nfi.NumberDecimalSeparator);
333                         }
334                         if (mantissa == 0) {
335                                 sb.Insert(0, "0");
336                         }
337                         else {
338                                 while (exponent > 0) {
339                                         sb.Insert(0, "0");
340                                         exponent--;
341                                 }
342                                 while (mantissa != 0) {
343                                         sb.Insert(0, (char)('0' + (mantissa % 10)));
344                                         mantissa /= 10;
345                                 }
346                         }
347                         if (value < 0.0) {
348                                 sb.Insert(0, nfi.NegativeSign);
349                         }
350                         return sb.ToString();
351                 }
352
353                 private string FormatGeneral (Format formatData, double value,
354                                 NumberFormatInfo nfi, int precision) {
355                         StringBuilder sb = new StringBuilder();
356                         if (value == 0.0) {
357                                 sb.Append("0");
358                         }
359                         else {
360                                 precision = (precision > 0) ?
361                                         precision : formatData.dec_len+1;
362                                         
363                                 long mantissa;
364                                 int exponent;
365                                 Normalize (formatData, value, precision, out mantissa, out exponent);
366                                 if (precision > 0) {
367                                         double dmant = mantissa;
368                                         for (int i = 0; i < formatData.dec_len - precision + 1; i++) {
369                                                 dmant /= 10;
370                                         }
371                                         mantissa = (long) Math.Round (dmant);
372                                         for (int i = 0; i < formatData.dec_len - precision + 1; i++) {
373                                                 mantissa *= 10;
374                                         }
375                                 }
376                                 
377                                 /* Calculate the exponent we would get using the scientific notation */
378                                 int snExponent = exponent;
379                                 long snMantissa = mantissa;
380                         
381                                 while (snMantissa >= 10) {
382                                         snMantissa /= 10;
383                                         snExponent++;
384                                 }
385                                 
386                                 if (snExponent > -5 && snExponent < precision) {
387                                         bool not_null = false;
388                                         while (exponent < 0) {
389                                                 if ((not_null == false) && ((mantissa % 10) != 0)) {
390                                                         not_null = true;
391                                                 }
392                                                 if (not_null) {
393                                                         sb.Insert(0, (char)('0' + (mantissa % 10)));
394                                                 }
395                                                 mantissa /= 10;
396                                                 exponent++;
397                                         }
398                                         if (sb.Length != 0) {
399                                                 sb.Insert(0, nfi.NumberDecimalSeparator);
400                                         }
401                                         if (mantissa == 0) {
402                                                 sb.Insert(0, "0");
403                                         }
404                                         else {
405                                                 while (mantissa > 0) {
406                                                         sb.Insert(0, (char)('0' + (mantissa % 10)));
407                                                         mantissa /= 10;
408                                                 }
409                                         }
410                                 }
411                                 else {
412                                         bool not_null = false;
413                                         while (mantissa >= 10) {
414                                                 if ((not_null == false) && ((mantissa % 10) != 0)) {
415                                                         not_null = true;
416                                                 }
417                                                 if (not_null) {
418                                                         sb.Insert (0, (char)('0' + (mantissa % 10)));
419                                                 }
420                                                 mantissa /= 10;
421                                                 exponent++;
422                                         }
423                                         if (sb.Length != 0)
424                                           sb.Insert(0, nfi.NumberDecimalSeparator);
425                                         
426                                         sb.Insert(0, (char)('0' + (mantissa % 10)) );
427
428                                         if (exponent > 0) {
429                                                 sb.Append("E" + nfi.PositiveSign);
430                                         }
431                                         else {
432                                                 sb.Append("E" + nfi.NegativeSign);
433                                         }
434                                         sb.Append(Math.Abs(exponent).ToString("00"));
435                                 }
436                                 if (value < 0.0) {
437                                         sb.Insert(0, nfi.NegativeSign);
438                                 }
439                         }
440                         return sb.ToString();
441                 }
442
443                 private string FormatNumber (Format formatData, double value, NumberFormatInfo nfi, int precision) {
444                 
445                         precision = (precision >= 0) ? precision : nfi.NumberDecimalDigits;
446                         string numb = FormatNumberInternal (formatData, value, nfi, precision);
447                         if (value < 0) {
448                                 switch (nfi.NumberNegativePattern) {
449                                 case 0:
450                                         return "(" + numb + ")";
451                                 case 1:
452                                         return nfi.NegativeSign + numb;
453                                 case 2:
454                                         return nfi.NegativeSign + " " + numb;
455                                 case 3:
456                                         return numb + nfi.NegativeSign;
457                                 case 4:
458                                         return numb + " " + nfi.NegativeSign;
459                                 default:
460                                         throw new ArgumentException(Locale.GetText(
461                                                 "Invalid NumberNegativePattern"));
462                                 }
463                         }
464                         return numb;
465                 }
466
467                 private string FormatPercent (Format formatData, double value, NumberFormatInfo nfi,
468                                 int precision) {
469
470                         precision = (precision >= 0) ? precision : nfi.PercentDecimalDigits;
471                         string numb = FormatNumberInternal (formatData, value*100, nfi, precision);
472                         if (value < 0) {
473                                 switch (nfi.PercentNegativePattern) {
474                                 case 0:
475                                         return nfi.NegativeSign + numb + " " + nfi.PercentSymbol;
476                                 case 1:
477                                         return nfi.NegativeSign + numb + nfi.PercentSymbol;
478                                 case 2:
479                                         return nfi.NegativeSign + nfi.PercentSymbol + numb;
480                                 default:
481                                         throw new ArgumentException(Locale.GetText(
482                                                 "Invalid PercentNegativePattern"));
483                                 }
484                         }
485                         else {
486                                 switch (nfi.PercentPositivePattern) {
487                                 case 0:
488                                         return numb + " " + nfi.PercentSymbol;
489                                 case 1:
490                                         return numb + nfi.PercentSymbol;
491                                 case 2:
492                                         return nfi.PercentSymbol + numb;
493                                 default:
494                                         throw new ArgumentException(Locale.GetText(
495                                                 "invalid PercehtPositivePattern"));
496                                 }
497                         }
498                 }
499
500                 private string FormatNumberInternal (Format formatData, double value, NumberFormatInfo nfi, int precision) 
501                 {
502                         StringBuilder sb = new StringBuilder();
503                         int decimals = precision;
504                         long mantissa;
505                         int exponent;
506                         Normalize (formatData, value, precision, out mantissa, out exponent);
507                         if (exponent >= 0) {
508                                 while (decimals > 0) {
509                                         sb.Append("0");
510                                         decimals--;
511                                 }
512                         }
513                         else {
514                                 int decimal_limit = -(decimals + 1);
515                                 while (exponent < 0) {
516                                         if (exponent > decimal_limit) {
517                                                 sb.Insert(0, (char)('0' + (mantissa % 10)));
518                                         }
519                                         mantissa /= 10;
520                                         exponent++;
521                                         decimals--;
522                                 }
523                                 if (decimals > 0) {
524                                         sb.Append ('0', decimals);
525                                         decimals = 0;
526                                 }
527                         }
528                         if (precision != 0) {
529                                 sb.Insert(0, nfi.NumberDecimalSeparator);
530                         }
531                         if (mantissa == 0) {
532                                 sb.Insert(0, "0");
533                         }
534                         else {
535                                 int groupIndex = 0;
536                                 int groupPos = 0;
537                                 int groupSize = nfi.NumberGroupSizes[0];
538                                 if (groupSize == 0) groupSize = int.MaxValue;
539                                 
540                                 while (exponent > 0 || mantissa != 0) {
541                                         
542                                         if (groupPos == groupSize) {
543                                                 sb.Insert (0, nfi.NumberGroupSeparator);
544                                                 groupPos = 0;
545                                                 if (groupIndex < nfi.NumberGroupSizes.Length - 1) {
546                                                         groupIndex++;
547                                                         groupSize = nfi.NumberGroupSizes[groupIndex];
548                                                         if (groupSize == 0) groupSize = int.MaxValue;
549                                                 }
550                                         }
551                                         
552                                         if (exponent > 0) {
553                                                 sb.Insert (0, "0");
554                                                 exponent--;
555                                         }
556                                         else {
557                                                 sb.Insert(0, (char)('0' + (mantissa % 10)));
558                                                 mantissa /= 10;
559                                         }
560                                         
561                                         groupPos++;
562                                 }
563                         }
564                         return sb.ToString();
565                 }
566
567
568                 [MonoTODO]
569                 private string FormatReversible (Format formatData, double value, NumberFormatInfo nfi,
570                                 int precision) {
571                         return FormatGeneral (formatData, value, nfi, precision);
572                 }
573
574                 private string FormatCustom (Format formatData, double value,
575                                 NumberFormatInfo nfi, string format) {
576                         int first_semicolon, last_semicolon;
577                         first_semicolon = format.IndexOf(';');
578                         last_semicolon = format.LastIndexOf(';');
579                         if (first_semicolon == last_semicolon) {
580                                 if (first_semicolon == -1) {
581                                         if (value < 0.0) {
582                                                 string result = FormatCustomParser (formatData, value, nfi, format);
583                                                 if (result == "0") {
584                                                         return "0";
585                                                 }
586                                                 if (result.Length > 0) {
587                                                         result = "-" + result;
588                                                 }
589                                                 return result;
590                                         }
591                                         return FormatCustomParser (formatData, value, nfi, format);
592                                         
593                                 }
594                                 if (value < 0.0) {
595                                         return FormatCustomParser
596                                                 (formatData, value, nfi, format.Substring(first_semicolon + 1));
597                                 }
598                                 return FormatCustomParser (formatData, value, nfi,
599                                                 format.Substring(0, first_semicolon - 1));
600                         }
601                         if (value > 0.0) {
602                                 return FormatCustomParser (formatData, value, nfi,
603                                                 format.Substring(0, first_semicolon - 1));
604                         }
605                         else if (value < 0.0) {
606                                 return FormatCustomParser (formatData, value, nfi,
607                                                 format.Substring (first_semicolon + 1,
608                                                         last_semicolon - first_semicolon));
609                         }
610                         return FormatCustomParser (formatData, value, nfi,
611                                         format.Substring(last_semicolon + 1));
612                 }
613
614                 private struct Flags {
615                         public int NumberOfColons;
616                         public bool Groupping;
617                         public bool Percent;
618                         public int DotPos;
619                         public int ExpPos;
620                         public int FirstFormatPos;
621                         public int IntegralLength;
622                         public int DecimalLength;
623                         public int ExponentialLength;
624                 }
625
626                 private Flags AnalizeFormat (string format) {
627                         Flags f = new Flags();
628                         f.NumberOfColons = 0;
629                         f.DotPos = -1;
630                         f.ExpPos = -1;
631                         f.Groupping = false;
632                         f.Percent = false;
633                         f.FirstFormatPos = -1;
634                         int aux = 0, i = 0, count = 0;
635                         foreach (char c in format) {
636                                 switch (c) {
637                                 case ',':
638                                         aux++;
639                                         break;
640                                 case '0':
641                                 case '#':
642                                         if (f.FirstFormatPos < 0) {
643                                                 f.FirstFormatPos = i;
644                                         }
645                                         if (aux > 0) {
646                                                 f.Groupping = true;
647                                                 aux = 0;
648                                         }
649                                         count++;
650                                         break;
651                                 case '.':
652                                         f.DotPos = i;
653                                         f.IntegralLength = count;
654                                         count = 0;
655                                         if (aux > 0) {
656                                                 f.NumberOfColons = aux;
657                                                 aux = 0;
658                                         }
659                                         break;
660                                 case '%':
661                                         f.Percent = true;
662                                         break;
663                                 case 'e':
664                                 case 'E':
665                                         f.DecimalLength = count;
666                                         count = 0;
667                                         f.ExpPos = i;
668                                         break;
669                                 }
670                                 i++;
671                         }
672                         if (aux > 0) {
673                                 f.NumberOfColons = aux;
674                         }
675                         if (f.DecimalLength > 0) {
676                                 f.ExponentialLength = count;
677                         }
678                         else {
679                                 f.DecimalLength = count;
680                         }
681                         return f;
682                 }
683
684                 private string FormatCustomParser (Format formatData, double value,
685                                 NumberFormatInfo nfi, string format) {
686                         long mantissa;
687                         int exponent;
688                         Flags f = AnalizeFormat(format);
689                         if (f.FirstFormatPos < 0) {
690                                 return format;
691                         }
692                         if (((f.Percent) || (f.NumberOfColons > 0)) && (f.ExpPos < 0)) {
693                                 int len = f.DecimalLength;
694                                 int exp = 0;
695                                 if (f.Percent) {
696                                         len += 2;
697                                         exp += 2;
698                                 }
699                                 if (f.NumberOfColons > 0) {
700                                         len -= (3 * f.NumberOfColons);
701                                         exp -= 3 * f.NumberOfColons;
702                                 }
703                                 if (len < 0) {
704                                         len = 0;
705                                 }
706                                 value = Math.Round(value, len);
707                                 Normalize (formatData, value, 15, out mantissa, out exponent);
708                                 exponent += exp;
709                         }
710                         else {
711                                 value = Math.Round(value, f.DecimalLength);
712                                 Normalize (formatData, value, 15, out mantissa, out exponent);
713                         }
714                         StringBuilder sb = new StringBuilder();
715                         if (f.ExpPos > 0) {
716                                 StringBuilder sb_decimal = new StringBuilder();
717                                 while (mantissa > 0) {
718                                         sb_decimal.Insert(0, (char)('0' + (mantissa % 10)));
719                                         mantissa /= 10;
720                                         exponent++;
721                                 }
722                                 exponent--;
723                                 int k;
724                                 for (k = sb_decimal.Length - 1;
725                                         k >= 0 && sb_decimal[k] == '0'; k--);
726                                 sb_decimal.Remove(k + 1, sb_decimal.Length - k - 1);
727                                 for (int i = f.DotPos - 2; i >= 0; i--) {
728                                         char c = format[i];
729                                         if (i > 0 && format[i-1] == '\\') {
730                                                 sb.Insert(0, c);
731                                                 i -= 2;
732                                                 continue;
733                                         }
734                                         switch (c) {
735                                         case ',':
736                                         case '#':
737                                                 break;
738                                         case '0':
739                                                 sb.Insert(0, '0');
740                                                 break;
741                                         default:
742                                                 sb.Insert(0, c);
743                                                 break;
744                                         }
745                                 }
746                                 sb.Append(sb_decimal[0]);
747                                 sb.Append(nfi.NumberDecimalSeparator);
748                                 for (int j = 1, i = f.DotPos + 1; i < f.ExpPos; i++) {
749                                         char c = format[i];
750                                         switch (c) {
751                                         case '\\':
752                                                 sb.Append(format[++i]);
753                                                 break;
754                                         case '0':
755                                                 if (j >= sb_decimal.Length) {
756                                                         sb.Append('0');
757                                                         break;
758                                                 }
759                                                 goto case '#';
760                                         case '#':
761                                                 if (j < sb_decimal.Length) {
762                                                         if ((i == f.ExpPos - 1) &&
763                                                                         (j < sb_decimal.Length - 1)) {
764                                                                 int a = sb_decimal[j] - '0';
765                                                                 int b = sb_decimal[j+1] - '0';
766                                                                 if (((b == 5) && ((a % 2) == 0)) || (b > 5)) {
767                                                                         a++;
768                                                                 }
769                                                                 sb.Append((char)('0' + (a % 10)));
770                                                         }
771                                                         else {
772                                                                 sb.Append(sb_decimal[j++]);
773                                                         }
774                                                 }
775                                                 break;
776                                         default:
777                                                 sb.Append(c);
778                                                 break;
779                                         }
780                                 }
781                                 sb.Append(format[f.ExpPos]);
782                                 if (exponent < 0) {
783                                         sb.Append('-');
784                                 }
785                                 int fin, inicio;
786                                 inicio = f.ExpPos + 1;
787                                 if (format[inicio] == '-') {
788                                         inicio++;
789                                 }
790                                 else if (format[inicio] == '+') {
791                                         if (exponent >= 0) {
792                                                 sb.Append('+');
793                                         }
794                                         inicio++;
795                                 }
796                                 fin = inicio;
797                                 while (fin < format.Length && format[fin++] == '0');
798                                 StringBuilder sb_exponent = new StringBuilder();
799                                 exponent = Math.Abs(exponent);
800                                 while (exponent > 0) {
801                                         sb_exponent.Insert(0, (char)('0' + (exponent % 10)));
802                                         exponent /= 10;
803                                 }
804                                 while (sb_exponent.Length < (fin - inicio)) {
805                                         sb_exponent.Insert(0, '0');
806                                 }
807                                 sb.Append(sb_exponent.ToString());
808                                 for (int i = fin; i < format.Length; i++) {
809                                         sb.Append(format[i]);
810                                 }
811                                 return sb.ToString();
812                         }
813                         else {
814                                 f.ExpPos = format.Length;
815                         }
816                         if (f.DotPos < 0) {
817                                 while (exponent < 0) {
818                                         mantissa = (long) Math.Round((double)mantissa / 10);
819                                         exponent++;
820                                 }
821                                 f.DotPos = format.Length;
822                         }
823                         else {
824                                 StringBuilder sb_decimal = new StringBuilder();
825                                 while (exponent < 0) {
826                                         sb_decimal.Insert(0, (char)('0' + (mantissa % 10)));
827                                         mantissa /= 10;
828                                         exponent++;
829                                 }
830                                 int k;
831                                 for (k = sb_decimal.Length - 1;
832                                         k >= 0 && sb_decimal[k] == '0'; k--);
833                                 sb_decimal.Remove(k + 1, sb_decimal.Length - k - 1);
834                                 if (sb_decimal.Length > 0) {
835                                         sb.Append(nfi.NumberDecimalSeparator);
836                                 }
837                                 else if (format[f.DotPos + 1] == '0') {
838                                         sb.Append(nfi.NumberDecimalSeparator);
839                                 }
840                                 bool terminado = false;
841                                 for (int j = 0, i = f.DotPos + 1; i < f.ExpPos; i++) {
842                                         if (format[i] == '0' || format[i] == '#') {
843                                                 if (j < sb_decimal.Length) {
844                                                         sb.Append(sb_decimal[j++]);
845                                                 }
846                                                 else if (format[i] == '0' && !terminado) {
847                                                         sb.Append('0');
848                                                 }
849                                                 else if (format[i] == '#' && !terminado) {
850                                                         terminado = true;
851                                                 }
852                                         }
853                                         else if (format[i] == '\\') {
854                                                 sb.Append(format[++i]);
855                                         }
856                                         else {
857                                                 sb.Append(format[i]);
858                                         }
859                                 }
860                         }
861                         int gro = 0;
862                         for (int i = f.DotPos - 1; i >= f.FirstFormatPos; i--) {
863                                 if (format[i] == '#' || format[i] == '0') {
864                                         if (exponent > 0 || mantissa > 0 || format[i] == '0') {
865                                                 if (f.Groupping && gro == nfi.NumberGroupSizes[0]) {
866                                                         sb.Insert(0, nfi.NumberGroupSeparator);
867                                                         gro = 0;
868                                                 }
869                                                 gro++;
870                                                 if (exponent > 0) {
871                                                         sb.Insert(0, '0');
872                                                         exponent--;
873                                                 }
874                                                 else if (mantissa > 0) {
875                                                         sb.Insert(0, (char)('0' + (mantissa % 10)));
876                                                         mantissa /= 10;
877                                                 }
878                                                 else if (format[i] == '0') {
879                                                         sb.Insert(0, '0');
880                                                 }
881                                         }
882                                 }
883                                 else if (format[i] != ',') {
884                                         sb.Insert(0, format[i]);
885                                 }
886                                 else if (i > 0 && format[i-1] == '\\') {
887                                         sb.Insert(0, format[i]);
888                                         i -= 2;
889                                 }
890                         }
891                         while (exponent > 0) {
892                                 if (f.Groupping && gro == nfi.NumberGroupSizes[0]) {
893                                         sb.Insert(0, nfi.NumberGroupSeparator);
894                                         gro = 0;
895                                 }
896                                 gro++;
897                                 sb.Insert(0, '0');
898                                 exponent--;
899                         }
900                         while (mantissa > 0) {
901                                 if (f.Groupping && gro == nfi.NumberGroupSizes[0]) {
902                                         sb.Insert(0, nfi.NumberGroupSeparator);
903                                         gro = 0;
904                                 }
905                                 gro++;
906                                 sb.Insert(0, (char)('0' + (mantissa % 10)));
907                                 mantissa /= 10;
908                         }
909                         for (int i = f.FirstFormatPos - 1; i >= 0; i--) {
910                                 sb.Insert(0, format[i]);
911                         }
912                         return sb.ToString();
913                 }
914
915         }
916
917 }