Merge pull request #4222 from alexanderkyte/fix_mismatch_com_disabled
[mono.git] / mcs / class / corlib / System / NumberFormatter.cs
1 //
2 // System.NumberFormatter.cs
3 //
4 // Author:
5 //   Kazuki Oikawa (kazuki@panicode.com)
6 //   Eyal Alaluf (eyala@mainsoft.com)
7 //
8 // Copyright (C) 2004 Novell, Inc (http://www.novell.com)
9 // Copyright (C) 2008 Mainsoft Co. (http://www.mainsoft.com)
10 //
11 // Permission is hereby granted, free of charge, to any person obtaining
12 // a copy of this software and associated documentation files (the
13 // "Software"), to deal in the Software without restriction, including
14 // without limitation the rights to use, copy, modify, merge, publish,
15 // distribute, sublicense, and/or sell copies of the Software, and to
16 // permit persons to whom the Software is furnished to do so, subject to
17 // the following conditions:
18 // 
19 // The above copyright notice and this permission notice shall be
20 // included in all copies or substantial portions of the Software.
21 // 
22 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
23 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
24 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
25 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
26 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
27 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
28 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 //
30
31 using System.Globalization;
32 using System.Text;
33 using System.Threading;
34 using System.Runtime.CompilerServices;
35
36 namespace System
37 {
38         internal sealed partial class NumberFormatter
39         {
40                 #region Static Fields
41
42                 const int DefaultExpPrecision = 6;
43                 const int HundredMillion = 100000000;
44                 const long SeventeenDigitsThreshold = 10000000000000000;
45                 const ulong ULongDivHundredMillion = UInt64.MaxValue / HundredMillion;
46                 const ulong ULongModHundredMillion = 1 + UInt64.MaxValue % HundredMillion;
47
48                 const int DoubleBitsExponentShift = 52;
49                 const int DoubleBitsExponentMask = 0x7ff;
50                 const long DoubleBitsMantissaMask = 0xfffffffffffff;
51                 const int DecimalBitsScaleMask = 0x1f0000;
52
53                 const int SingleDefPrecision = 7;
54                 const int DoubleDefPrecision = 15;
55                 const int Int32DefPrecision = 10;
56                 const int UInt32DefPrecision = 10;
57                 const int Int64DefPrecision = 19;
58                 const int UInt64DefPrecision = 20;
59                 const int DecimalDefPrecision = 100;
60                 const int TenPowersListLength = 19;
61
62                 const double MinRoundtripVal = -1.79769313486231E+308;
63                 const double MaxRoundtripVal = 1.79769313486231E+308;
64
65                 // The below arrays are taken from mono/metatdata/number-formatter.h
66
67                 private static readonly unsafe ulong* MantissaBitsTable;
68                 private static readonly unsafe int* TensExponentTable;
69                 private static readonly unsafe char* DigitLowerTable;
70                 private static readonly unsafe char* DigitUpperTable;
71                 private static readonly unsafe long* TenPowersList;
72
73                 // DecHexDigits s a translation table from a decimal number to its
74                 // digits hexadecimal representation (e.g. DecHexDigits [34] = 0x34).
75                 private static readonly unsafe int* DecHexDigits;
76
77                 [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
78                 private unsafe static extern void GetFormatterTables (out ulong* MantissaBitsTable, out int* TensExponentTable,
79                                 out char* DigitLowerTable, out char* DigitUpperTable,
80                                 out long* TenPowersList, out int* DecHexDigits);
81
82                 unsafe static NumberFormatter()
83                 {
84                         GetFormatterTables (out MantissaBitsTable, out TensExponentTable,
85                                 out DigitLowerTable, out DigitUpperTable, out TenPowersList, out DecHexDigits);
86                 }
87
88                 unsafe static long GetTenPowerOf(int i)
89                 {
90                         return TenPowersList [i];
91                 }
92                 #endregion Static Fields
93
94                 #region Fields
95
96                 private NumberFormatInfo _nfi;
97
98                 //part of the private stringbuffer
99                 private char[] _cbuf;
100
101                 private bool _NaN;
102                 private bool _infinity;
103                 private bool _isCustomFormat;
104                 private bool _specifierIsUpper;
105                 private bool _positive;
106                 private char _specifier;
107                 private int _precision;
108                 private int _defPrecision;
109
110                 private int _digitsLen;
111                 private int _offset; // Represent the first digit offset.
112                 private int _decPointPos;
113
114                 // The following fields are a hexadeimal representation of the digits.
115                 // For instance _val = 0x234 represents the digits '2', '3', '4'.
116                 private uint _val1; // Digits 0 - 7.
117                 private uint _val2; // Digits 8 - 15.
118                 private uint _val3; // Digits 16 - 23.
119                 private uint _val4; // Digits 23 - 31. Only needed for decimals.
120
121                 #endregion Fields
122
123                 #region Constructor Helpers
124
125                 // Translate an unsigned int to hexadecimal digits.
126                 // i.e. 123456789 is represented by _val1 = 0x23456789 and _val2 = 0x1
127                 private void InitDecHexDigits (uint value)
128                 {
129                         if (value >= HundredMillion) {
130                                 int div1 = (int)(value / HundredMillion);
131                                 value -= HundredMillion * (uint)div1;
132                                 _val2 = FastToDecHex (div1);
133                         }
134                         _val1 = ToDecHex ((int)value);
135                 }
136
137                 // Translate an unsigned long to hexadecimal digits.
138                 private void InitDecHexDigits (ulong value)
139                 {
140                         if (value >= HundredMillion) {
141                                 long div1 = (long)(value / HundredMillion);
142                                 value -= HundredMillion * (ulong)div1;
143                                 if (div1 >= HundredMillion) {
144                                         int div2 = (int)(div1 / HundredMillion);
145                                         div1 = div1 - div2 * (long)HundredMillion;
146                                         _val3 = ToDecHex (div2);
147                                 }
148                                 if (div1 != 0)
149                                         _val2 = ToDecHex ((int)(div1));
150                         }
151                         if (value != 0)
152                                 _val1 = ToDecHex ((int)value);
153                 }
154
155                 // Translate a decimal integer to hexadecimal digits.
156                 // The decimal integer is 96 digits and its value is hi * 2^64 + lo.
157                 // is the lower 64 bits.
158                 private void InitDecHexDigits (uint hi, ulong lo)
159                 {
160                         if (hi == 0) {
161                                 InitDecHexDigits (lo); // Only the lower 64 bits matter.
162                                 return;
163                         }
164
165                         // Compute (hi, lo) = (hi , lo) / HundredMillion.
166                         uint divhi = hi / HundredMillion;
167                         ulong remhi = hi - divhi * HundredMillion;
168                         ulong divlo = lo / HundredMillion;
169                         ulong remlo = lo - divlo * HundredMillion + remhi * ULongModHundredMillion;
170                         hi = divhi;
171                         lo = divlo + remhi * ULongDivHundredMillion;
172                         divlo = remlo / HundredMillion;
173                         remlo -= divlo * HundredMillion;
174                         lo += divlo;
175                         _val1 = ToDecHex ((int)remlo);
176
177                         // Divide hi * 2 ^ 64 + lo by HundredMillion using the fact that
178                         // hi < HundredMillion.
179                         divlo = lo / HundredMillion;
180                         remlo = lo - divlo * HundredMillion;
181                         lo = divlo;
182                         if (hi != 0) {
183                                 lo += hi * ULongDivHundredMillion;
184                                 remlo += hi * ULongModHundredMillion;
185                                 divlo = remlo / HundredMillion;
186                                 lo += divlo;
187                                 remlo -= divlo * HundredMillion;
188                         }
189                         _val2 = ToDecHex ((int)remlo);
190
191                         // Now we are left with 64 bits store in lo.
192                         if (lo >= HundredMillion) {
193                                 divlo = lo / HundredMillion;
194                                 lo -= divlo * HundredMillion;
195                                 _val4 = ToDecHex ((int)divlo);
196                         }
197                         _val3 = ToDecHex ((int)lo);
198                 }
199
200                 // Helper to translate an int in the range 0 .. 9999 to its
201                 // Hexadecimal digits representation.
202                 unsafe private static uint FastToDecHex (int val)
203                 {
204                         if (val < 100)
205                                 return (uint)DecHexDigits [val];
206
207                         // Uses 2^19 (524288) to compute val / 100 for val < 10000.
208                         int v = (val * 5243) >> 19;
209                         return (uint)((DecHexDigits [v] << 8) | DecHexDigits [val - v * 100]);
210                 }
211
212                 // Helper to translate an int in the range 0 .. 99999999 to its
213                 // Hexadecimal digits representation.
214                 private static uint ToDecHex (int val)
215                 {
216                         uint res = 0;
217                         if (val >= 10000) {
218                                 int v = val / 10000;
219                                 val -= v * 10000;
220                                 res = FastToDecHex (v) << 16;
221                         }
222                         return res | FastToDecHex (val);
223                 }
224
225                 // Helper to count number of hexadecimal digits in a number.
226                 private static int FastDecHexLen (int val)
227                 {
228                         if (val < 0x100)
229                                 if (val < 0x10)
230                                         return 1;
231                                 else
232                                         return 2;
233                         else if (val < 0x1000)
234                                 return 3;
235                         else
236                                 return 4;
237                 }
238
239                 private static int DecHexLen (uint val)
240                 {
241                         if (val < 0x10000)
242                                 return FastDecHexLen ((int)val);
243                         return 4 + FastDecHexLen ((int)(val >> 16));
244                 }
245
246                 // Count number of hexadecimal digits stored in _val1 .. _val4.
247                 private int DecHexLen ()
248                 {
249                         if (_val4 != 0)
250                                 return DecHexLen (_val4) + 24;
251                         else if (_val3 != 0)
252                                 return DecHexLen (_val3) + 16;
253                         else if (_val2 != 0)
254                                 return DecHexLen (_val2) + 8;
255                         else if (_val1 != 0)
256                                 return DecHexLen (_val1);
257                         else
258                                 return 0;
259                 }
260
261                 // Helper to count the 10th scale (number of digits) in a number
262                 private static int ScaleOrder (long hi)
263                 {
264                         for (int i = TenPowersListLength - 1; i >= 0; i--)
265                                 if (hi >= GetTenPowerOf (i))
266                                         return i + 1;
267                         return 1;
268                 }
269
270                 // Compute the initial precision for rounding a floating number
271                 // according to the used format.
272                 int InitialFloatingPrecision ()
273                 {
274                         if (_specifier == 'R')
275                                 return _defPrecision + 2;
276                         if (_precision < _defPrecision)
277                                 return _defPrecision;
278                         if (_specifier == 'G')
279                                 return Math.Min (_defPrecision + 2, _precision);
280                         if (_specifier == 'E')
281                                 return Math.Min (_defPrecision + 2, _precision + 1);
282                         return _defPrecision;
283                 }
284
285                 // Parse the given format and extract the precision in it.
286                 // Returns -1 for empty formats and -2 to indicate that the format
287                 // is a custom format.
288                 private static int ParsePrecision (string format)
289                 {
290                         int precision = 0;
291                         for (int i = 1; i < format.Length; i++) {
292                                 int val = format [i] - '0';
293                                 precision = precision * 10 + val;
294                                 if (val < 0 || val > 9 || precision > 99)
295                                         return -2;
296                         }
297                         return precision;
298                 }
299
300                 #endregion Constructor Helpers
301
302                 #region Constructors
303
304                 // Parse the given format and initialize the following fields:
305                 //   _isCustomFormat, _specifierIsUpper, _specifier & _precision.
306                 NumberFormatter (Thread current)
307                 {
308                         _cbuf = EmptyArray<char>.Value;
309                         if (current == null)
310                                 return;
311                         CurrentCulture = current.CurrentCulture;
312                 }
313
314                 private void Init (string format)
315                 {
316                         _val1 = _val2 = _val3 = _val4 = 0;
317                         _offset = 0;
318                         _NaN = _infinity = false;
319                         _isCustomFormat = false;
320                         _specifierIsUpper = true;
321                         _precision = -1;
322
323                         if (format == null || format.Length == 0) {
324                                 _specifier = 'G';
325                                 return;
326                         }
327
328                         char specifier = format [0];
329                         if (specifier >= 'a' && specifier <= 'z') {
330                                 specifier = (char)(specifier - 'a' + 'A');
331                                 _specifierIsUpper = false;
332                         }
333                         else if (specifier < 'A' || specifier > 'Z') {
334                                 _isCustomFormat = true;
335                                 _specifier = '0';
336                                 return;
337                         }
338                         _specifier = specifier;
339                         if (format.Length > 1) {
340                                 _precision = ParsePrecision (format);
341                                 if (_precision == -2) { // Is it a custom format?
342                                         _isCustomFormat = true;
343                                         _specifier = '0';
344                                         _precision = -1;
345                                 }
346                         }
347                 }
348
349                 private void InitHex (ulong value)
350                 {
351                         switch (_defPrecision) {
352                                 case Int32DefPrecision: value = (uint) value;    break;
353                         }
354                         _val1 = (uint)value;
355                         _val2 = (uint)(value >> 32);
356                         _decPointPos = _digitsLen = DecHexLen ();
357                         if (value == 0)
358                                 _decPointPos = 1;
359                 }
360
361                 private void Init (string format, int value, int defPrecision)
362                 {
363                         Init (format);
364                         _defPrecision = defPrecision;
365                         _positive = value >= 0;
366
367                         if (value == 0 || _specifier == 'X') {
368                                 InitHex ((ulong)value);
369                                 return;
370                         }
371
372                         if (value < 0)
373                                 value = -value;
374                         InitDecHexDigits ((uint)value);
375                         _decPointPos = _digitsLen = DecHexLen ();
376                 }
377
378                 private void Init (string format, uint value, int defPrecision)
379                 {
380                         Init (format);
381                         _defPrecision = defPrecision;
382                         _positive = true;
383
384                         if (value == 0 || _specifier == 'X') {
385                                 InitHex (value);
386                                 return;
387                         }
388
389                         InitDecHexDigits (value);
390                         _decPointPos = _digitsLen = DecHexLen ();
391                 }
392
393                 private void Init (string format, long value)
394                 {
395                         Init (format);
396                         _defPrecision = Int64DefPrecision;
397                         _positive = value >= 0;
398
399                         if (value == 0 || _specifier == 'X') {
400                                 InitHex ((ulong)value);
401                                 return;
402                         }
403
404                         if (value < 0)
405                                 value = -value;
406                         InitDecHexDigits ((ulong)value);
407                         _decPointPos = _digitsLen = DecHexLen ();
408                 }
409
410                 private void Init (string format, ulong value)
411                 {
412                         Init (format);
413                         _defPrecision = UInt64DefPrecision;
414                         _positive = true;
415
416                         if (value == 0 || _specifier == 'X') {
417                                 InitHex ((ulong)value);
418                                 return;
419                         }
420
421                         InitDecHexDigits (value);
422                         _decPointPos = _digitsLen = DecHexLen ();
423                 }
424
425                 unsafe private void Init (string format, double value, int defPrecision)
426                 {
427                         Init (format);
428
429                         _defPrecision = defPrecision;
430                         long bits = BitConverter.DoubleToInt64Bits (value);
431                         _positive = bits >= 0;
432                         bits &= Int64.MaxValue;
433                         if (bits == 0) {
434                                 _decPointPos = 1;
435                                 _digitsLen = 0;
436                                 _positive = true;
437                                 return;
438                         }
439
440                         int e = (int)(bits >> DoubleBitsExponentShift);
441                         long m = bits & DoubleBitsMantissaMask;
442                         if (e == DoubleBitsExponentMask) {
443                                 _NaN = m != 0;
444                                 _infinity = m == 0;
445                                 return;
446                         }
447
448                         int expAdjust = 0;
449                         if (e == 0) {
450                                 // We need 'm' to be large enough so we won't lose precision.
451                                 e = 1;
452                                 int scale = ScaleOrder (m);
453                                 if (scale < DoubleDefPrecision) {
454                                         expAdjust = scale - DoubleDefPrecision;
455                                         m *= GetTenPowerOf (-expAdjust);
456                                 }
457                         }
458                         else {
459                                 m = (m + DoubleBitsMantissaMask + 1) * 10;
460                                 expAdjust = -1;
461                         }
462
463                         // multiply the mantissa by 10 ^ N
464                         ulong lo = (uint)m;
465                         ulong hi = (ulong)m >> 32;
466                         ulong lo2 = MantissaBitsTable [e];
467                         ulong hi2 = lo2 >> 32;
468                         lo2 = (uint)lo2;
469                         ulong mm = hi * lo2 + lo * hi2 + ((lo * lo2) >> 32);
470                         long res = (long)(hi * hi2 + (mm >> 32));
471                         while (res < SeventeenDigitsThreshold) {
472                                 mm = (mm & UInt32.MaxValue) * 10;
473                                 res = res * 10 + (long)(mm >> 32);
474                                 expAdjust--;
475                         }
476                         if ((mm & 0x80000000) != 0)
477                                 res++;
478
479                         int order = DoubleDefPrecision + 2;
480                         _decPointPos = TensExponentTable [e] + expAdjust + order;
481
482                         // Rescale 'res' to the initial precision (15-17 for doubles).
483                         int initialPrecision = InitialFloatingPrecision ();
484                         if (order > initialPrecision) {
485                                 long val = GetTenPowerOf (order - initialPrecision);
486                                 res = (res + (val >> 1)) / val;
487                                 order = initialPrecision;
488                         }
489                         if (res >= GetTenPowerOf (order)) {
490                                 order++;
491                                 _decPointPos++;
492                         }
493
494                         InitDecHexDigits ((ulong)res);
495                         _offset = CountTrailingZeros ();
496                         _digitsLen = order - _offset;
497                 }
498
499                 private void Init (string format, decimal value)
500                 {
501                         Init (format);
502                         _defPrecision = DecimalDefPrecision;
503
504                         int[] bits = decimal.GetBits (value);
505                         int scale = (bits [3] & DecimalBitsScaleMask) >> 16;
506                         _positive = bits [3] >= 0;
507                         if (bits [0] == 0 && bits [1] == 0 && bits [2] == 0) {
508                                 _decPointPos = -scale;
509                                 _positive = true;
510                                 _digitsLen = 0;
511                                 return;
512                         }
513
514                         InitDecHexDigits ((uint)bits [2], ((ulong)bits [1] << 32) | (uint)bits [0]);
515                         _digitsLen = DecHexLen ();
516                         _decPointPos = _digitsLen - scale;
517                         if (_precision != -1 || _specifier != 'G') {
518                                 _offset = CountTrailingZeros ();
519                                 _digitsLen -= _offset;
520                         }
521                 }
522
523                 #endregion Constructors
524
525                 #region Inner String Buffer
526
527                 //_cbuf moved to before other fields to improve layout
528                 private int _ind;
529
530                 private void ResetCharBuf (int size)
531                 {
532                         _ind = 0;
533                         if (_cbuf.Length < size)
534                                 _cbuf = new char [size];
535                 }
536
537                 private void Resize (int len)
538                 {
539                         Array.Resize (ref _cbuf, len);
540                 }
541
542                 private void Append (char c)
543                 {
544                         if (_ind == _cbuf.Length)
545                                 Resize (_ind + 10);
546                         _cbuf [_ind++] = c;
547                 }
548
549                 private void Append (char c, int cnt)
550                 {
551                         if (_ind + cnt > _cbuf.Length)
552                                 Resize (_ind + cnt + 10);
553                         while (cnt-- > 0)
554                                 _cbuf [_ind++] = c;
555                 }
556
557                 private void Append (string s)
558                 {
559                         int slen = s.Length;
560                         if (_ind + slen > _cbuf.Length)
561                                 Resize (_ind + slen + 10);
562                         for (int i = 0; i < slen; i++)
563                                 _cbuf [_ind++] = s [i];
564                 }
565
566                 #endregion Inner String Buffer
567
568                 #region Helper properties
569
570                 private NumberFormatInfo GetNumberFormatInstance (IFormatProvider fp)
571                 {
572                         if (_nfi != null && fp == null)
573                                 return _nfi;
574                         return NumberFormatInfo.GetInstance (fp);
575                 }
576
577                 CultureInfo CurrentCulture {
578                         set {
579                                 if (value != null && value.IsReadOnly)
580                                         _nfi = value.NumberFormat;
581                                 else
582                                         _nfi = null;
583                         }
584                 }
585
586                 private int IntegerDigits {
587                         get { return _decPointPos > 0 ? _decPointPos : 1; }
588                 }
589
590                 private int DecimalDigits {
591                         get { return _digitsLen > _decPointPos ? _digitsLen - _decPointPos : 0; }
592                 }
593
594                 private bool IsFloatingSource {
595                         get { return _defPrecision == DoubleDefPrecision || _defPrecision == SingleDefPrecision; }
596                 }
597
598                 private bool IsZero {
599                         get { return _digitsLen == 0; }
600                 }
601
602                 private bool IsZeroInteger {
603                         get { return _digitsLen == 0 || _decPointPos <= 0; }
604                 }
605
606                 #endregion Helper properties
607
608                 #region Round
609
610                 private void RoundPos (int pos)
611                 {
612                         RoundBits (_digitsLen - pos);
613                 }
614
615                 private bool RoundDecimal (int decimals)
616                 {
617                         return RoundBits (_digitsLen - _decPointPos - decimals);
618                 }
619
620                 private bool RoundBits (int shift)
621                 {
622                         if (shift <= 0)
623                                 return false;
624
625                         if (shift > _digitsLen) {
626                                 _digitsLen = 0;
627                                 _decPointPos = 1;
628                                 _val1 = _val2 = _val3 = _val4 = 0;
629                                 _positive = true;
630                                 return false;
631                         }
632                         shift += _offset;
633                         _digitsLen += _offset;
634                         while (shift > 8) {
635                                 _val1 = _val2;
636                                 _val2 = _val3;
637                                 _val3 = _val4;
638                                 _val4 = 0;
639                                 _digitsLen -= 8;
640                                 shift -= 8;
641                         }
642                         shift = (shift - 1) << 2;
643                         uint v = _val1 >> shift;
644                         uint rem16 = v & 0xf;
645                         _val1 = (v ^ rem16) << shift;
646                         bool res = false;
647                         if (rem16 >= 0x5) {
648                                 _val1 |= 0x99999999 >> (28 - shift);
649                                 AddOneToDecHex ();
650                                 int newlen = DecHexLen ();
651                                 res = newlen != _digitsLen;
652                                 _decPointPos = _decPointPos + newlen - _digitsLen;
653                                 _digitsLen = newlen;
654                         }
655                         RemoveTrailingZeros ();
656                         return res;
657                 }
658
659                 private void RemoveTrailingZeros ()
660                 {
661                         _offset = CountTrailingZeros ();
662                         _digitsLen -= _offset;
663                         if (_digitsLen == 0) {
664                                 _offset = 0;
665                                 _decPointPos = 1;
666                                 _positive = true;
667                         }
668                 }
669
670                 private void AddOneToDecHex ()
671                 {
672                         if (_val1 == 0x99999999) {
673                                 _val1 = 0;
674                                 if (_val2 == 0x99999999) {
675                                         _val2 = 0;
676                                         if (_val3 == 0x99999999) {
677                                                 _val3 = 0;
678                                                 _val4 = AddOneToDecHex (_val4);
679                                         }
680                                         else
681                                                 _val3 = AddOneToDecHex (_val3);
682                                 }
683                                 else
684                                         _val2 = AddOneToDecHex (_val2);
685                         }
686                         else
687                                 _val1 = AddOneToDecHex (_val1);
688                 }
689
690                 // Assume val != 0x99999999
691                 private static uint AddOneToDecHex (uint val)
692                 {
693                         if ((val & 0xffff) == 0x9999)
694                                 if ((val & 0xffffff) == 0x999999)
695                                         if ((val & 0xfffffff) == 0x9999999)
696                                                 return val + 0x06666667;
697                                         else
698                                                 return val + 0x00666667;
699                                 else if ((val & 0xfffff) == 0x99999)
700                                         return val + 0x00066667;
701                                 else
702                                         return val + 0x00006667;
703                         else if ((val & 0xff) == 0x99)
704                                 if ((val & 0xfff) == 0x999)
705                                         return val + 0x00000667;
706                                 else
707                                         return val + 0x00000067;
708                         else if ((val & 0xf) == 0x9)
709                                 return val + 0x00000007;
710                         else
711                                 return val + 1;
712                 }
713
714                 private int CountTrailingZeros ()
715                 {
716                         if (_val1 != 0)
717                                 return CountTrailingZeros (_val1);
718                         if (_val2 != 0)
719                                 return CountTrailingZeros (_val2) + 8;
720                         if (_val3 != 0)
721                                 return CountTrailingZeros (_val3) + 16;
722                         if (_val4 != 0)
723                                 return CountTrailingZeros (_val4) + 24;
724                         return _digitsLen;
725                 }
726
727                 private static int CountTrailingZeros (uint val)
728                 {
729                         if ((val & 0xffff) == 0)
730                                 if ((val & 0xffffff) == 0)
731                                         if ((val & 0xfffffff) == 0)
732                                                 return 7;
733                                         else
734                                                 return 6;
735                                 else if ((val & 0xfffff) == 0)
736                                         return 5;
737                                 else
738                                         return 4;
739                         else if ((val & 0xff) == 0)
740                                 if ((val & 0xfff) == 0)
741                                         return 3;
742                                 else
743                                         return 2;
744                         else if ((val & 0xf) == 0)
745                                 return 1;
746                         else
747                                 return 0;
748                 }
749
750                 #endregion Round
751
752                 #region public number formatting methods
753
754                 [ThreadStatic]
755                 static NumberFormatter threadNumberFormatter;
756
757                 [ThreadStatic]
758                 static NumberFormatter userFormatProvider;
759
760                 private static NumberFormatter GetInstance (IFormatProvider fp)
761                 {
762                         if (fp != null) {
763                                 if (userFormatProvider == null) {
764                                         Interlocked.CompareExchange (ref userFormatProvider, new NumberFormatter (null), null);
765                                 }
766
767                                 return userFormatProvider;
768                         }
769
770                         NumberFormatter res = threadNumberFormatter;
771                         threadNumberFormatter = null;
772                         if (res == null)
773                                 return new NumberFormatter (Thread.CurrentThread);
774                         res.CurrentCulture = Thread.CurrentThread.CurrentCulture;
775                         return res;
776                 }
777
778                 private void Release()
779                 {
780                         if (this != userFormatProvider)
781                                 threadNumberFormatter = this;
782                 }
783
784                 public static string NumberToString (string format, uint value, IFormatProvider fp)
785                 {
786                         NumberFormatter inst = GetInstance (fp);
787                         inst.Init (format, value, Int32DefPrecision);
788                         string res = inst.IntegerToString (format, fp);
789                         inst.Release();
790                         return res;
791                 }
792
793                 public static string NumberToString (string format, int value, IFormatProvider fp)
794                 {
795                         NumberFormatter inst = GetInstance (fp);
796                         inst.Init (format, value, UInt32DefPrecision);
797                         string res = inst.IntegerToString (format, fp);
798                         inst.Release();
799                         return res;
800                 }
801
802                 public static string NumberToString (string format, ulong value, IFormatProvider fp)
803                 {
804                         NumberFormatter inst = GetInstance (fp);
805                         inst.Init (format, value);
806                         string res = inst.IntegerToString (format, fp);
807                         inst.Release();
808                         return res;
809                 }
810
811                 public static string NumberToString (string format, long value, IFormatProvider fp)
812                 {
813                         NumberFormatter inst = GetInstance (fp);
814                         inst.Init (format, value);
815                         string res = inst.IntegerToString (format, fp);
816                         inst.Release();
817                         return res;
818                 }
819
820                 public static string NumberToString (string format, float value, IFormatProvider fp)
821                 {
822                         NumberFormatter inst = GetInstance (fp);
823                         inst.Init (format, value, SingleDefPrecision);
824                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
825                         string res;
826                         if (inst._NaN)
827                                 res = nfi.NaNSymbol;
828                         else if (inst._infinity)
829                                 if (inst._positive)
830                                         res = nfi.PositiveInfinitySymbol;
831                                 else
832                                         res = nfi.NegativeInfinitySymbol;
833                         else if (inst._specifier == 'R')
834                                 res = inst.FormatRoundtrip (value, nfi);
835                         else
836                                 res = inst.NumberToString (format, nfi);
837                         inst.Release();
838                         return res;
839                 }
840
841                 public static string NumberToString (string format, double value, IFormatProvider fp)
842                 {
843                         NumberFormatter inst = GetInstance (fp);
844                         inst.Init (format, value, DoubleDefPrecision);
845                         NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
846                         string res;
847                         if (inst._NaN)
848                                 res = nfi.NaNSymbol;
849                         else if (inst._infinity)
850                                 if (inst._positive)
851                                         res = nfi.PositiveInfinitySymbol;
852                                 else
853                                         res = nfi.NegativeInfinitySymbol;
854                         else if (inst._specifier == 'R')
855                                 res = inst.FormatRoundtrip (value, nfi);
856                         else
857                                 res = inst.NumberToString (format, nfi);
858                         inst.Release();
859                         return res;
860                 }
861
862                 public static string NumberToString (string format, decimal value, IFormatProvider fp)
863                 {
864                         NumberFormatter inst = GetInstance (fp);
865                         inst.Init (format, value);
866                         string res = inst.NumberToString (format, inst.GetNumberFormatInstance (fp));
867                         inst.Release();
868                         return res;
869                 }
870
871                 private string IntegerToString (string format, IFormatProvider fp)
872                 {
873                         NumberFormatInfo nfi = GetNumberFormatInstance (fp);
874                         switch (_specifier) {
875                         case 'C':
876                                 return FormatCurrency (_precision, nfi);
877                         case 'D':
878                                 return FormatDecimal (_precision, nfi);
879                         case 'E':
880                                 return FormatExponential (_precision, nfi);
881                         case 'F':
882                                 return FormatFixedPoint (_precision, nfi);
883                         case 'G':
884                                 if (_precision <= 0)
885                                         return FormatDecimal (-1, nfi);
886                                 return FormatGeneral (_precision, nfi);
887                         case 'N':
888                                 return FormatNumber (_precision, nfi);
889                         case 'P':
890                                 return FormatPercent (_precision, nfi);
891                         case 'X':
892                                 return FormatHexadecimal (_precision);
893                         default:
894                                 if (_isCustomFormat)
895                                         return FormatCustom (format, nfi);
896                                 throw new FormatException ("The specified format '" + format + "' is invalid");
897                         }
898                 }
899
900                 private string NumberToString (string format, NumberFormatInfo nfi)
901                 {
902                         switch (_specifier) {
903                         case 'C':
904                                 return FormatCurrency (_precision, nfi);
905                         case 'E':
906                                 return FormatExponential (_precision, nfi);
907                         case 'F':
908                                 return FormatFixedPoint (_precision, nfi);
909                         case 'G':
910                                 return FormatGeneral (_precision, nfi);
911                         case 'N':
912                                 return FormatNumber (_precision, nfi);
913                         case 'P':
914                                 return FormatPercent (_precision, nfi);
915                         case 'X':
916                         default:
917                                 if (_isCustomFormat)
918                                         return FormatCustom (format, nfi);
919                                 throw new FormatException ("The specified format '" + format + "' is invalid");
920                         }
921                 }
922
923                 string FormatCurrency (int precision, NumberFormatInfo nfi)
924                 {
925                         precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
926                         RoundDecimal (precision);
927                         ResetCharBuf (IntegerDigits * 2 + precision * 2 + 16);
928
929                         if (_positive) {
930                                 switch (nfi.CurrencyPositivePattern) {
931                                 case 0:
932                                         Append (nfi.CurrencySymbol);
933                                         break;
934                                 case 2:
935                                         Append (nfi.CurrencySymbol);
936                                         Append (' ');
937                                         break;
938                                 }
939                         }
940                         else {
941                                 switch (nfi.CurrencyNegativePattern) {
942                                 case 0:
943                                         Append ('(');
944                                         Append (nfi.CurrencySymbol);
945                                         break;
946                                 case 1:
947                                         Append (nfi.NegativeSign);
948                                         Append (nfi.CurrencySymbol);
949                                         break;
950                                 case 2:
951                                         Append (nfi.CurrencySymbol);
952                                         Append (nfi.NegativeSign);
953                                         break;
954                                 case 3:
955                                         Append (nfi.CurrencySymbol);
956                                         break;
957                                 case 4:
958                                         Append ('(');
959                                         break;
960                                 case 5:
961                                         Append (nfi.NegativeSign);
962                                         break;
963                                 case 8:
964                                         Append (nfi.NegativeSign);
965                                         break;
966                                 case 9:
967                                         Append (nfi.NegativeSign);
968                                         Append (nfi.CurrencySymbol);
969                                         Append (' ');
970                                         break;
971                                 case 11:
972                                         Append (nfi.CurrencySymbol);
973                                         Append (' ');
974                                         break;
975                                 case 12:
976                                         Append (nfi.CurrencySymbol);
977                                         Append (' ');
978                                         Append (nfi.NegativeSign);
979                                         break;
980                                 case 14:
981                                         Append ('(');
982                                         Append (nfi.CurrencySymbol);
983                                         Append (' ');
984                                         break;
985                                 case 15:
986                                         Append ('(');
987                                         break;
988                                 }
989                         }
990
991                         AppendIntegerStringWithGroupSeparator (nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
992
993                         if (precision > 0) {
994                                 Append (nfi.CurrencyDecimalSeparator);
995                                 AppendDecimalString (precision);
996                         }
997
998                         if (_positive) {
999                                 switch (nfi.CurrencyPositivePattern) {
1000                                 case 1:
1001                                         Append (nfi.CurrencySymbol);
1002                                         break;
1003                                 case 3:
1004                                         Append (' ');
1005                                         Append (nfi.CurrencySymbol);
1006                                         break;
1007                                 }
1008                         }
1009                         else {
1010                                 switch (nfi.CurrencyNegativePattern) {
1011                                 case 0:
1012                                         Append (')');
1013                                         break;
1014                                 case 3:
1015                                         Append (nfi.NegativeSign);
1016                                         break;
1017                                 case 4:
1018                                         Append (nfi.CurrencySymbol);
1019                                         Append (')');
1020                                         break;
1021                                 case 5:
1022                                         Append (nfi.CurrencySymbol);
1023                                         break;
1024                                 case 6:
1025                                         Append (nfi.NegativeSign);
1026                                         Append (nfi.CurrencySymbol);
1027                                         break;
1028                                 case 7:
1029                                         Append (nfi.CurrencySymbol);
1030                                         Append (nfi.NegativeSign);
1031                                         break;
1032                                 case 8:
1033                                         Append (' ');
1034                                         Append (nfi.CurrencySymbol);
1035                                         break;
1036                                 case 10:
1037                                         Append (' ');
1038                                         Append (nfi.CurrencySymbol);
1039                                         Append (nfi.NegativeSign);
1040                                         break;
1041                                 case 11:
1042                                         Append (nfi.NegativeSign);
1043                                         break;
1044                                 case 13:
1045                                         Append (nfi.NegativeSign);
1046                                         Append (' ');
1047                                         Append (nfi.CurrencySymbol);
1048                                         break;
1049                                 case 14:
1050                                         Append (')');
1051                                         break;
1052                                 case 15:
1053                                         Append (' ');
1054                                         Append (nfi.CurrencySymbol);
1055                                         Append (')');
1056                                         break;
1057                                 }
1058                         }
1059
1060                         return new string (_cbuf, 0, _ind);
1061                 }
1062
1063                 private string FormatDecimal (int precision, NumberFormatInfo nfi)
1064                 {
1065                         if (precision < _digitsLen)
1066                                 precision = _digitsLen;
1067                         if (precision == 0)
1068                                 return "0";
1069
1070                         ResetCharBuf (precision + 1);
1071                         if (!_positive)
1072                                 Append (nfi.NegativeSign);
1073                         AppendDigits (0, precision);
1074
1075                         return new string (_cbuf, 0, _ind);
1076                 }
1077
1078                 unsafe private string FormatHexadecimal (int precision)
1079                 {
1080                         int size = Math.Max (precision, _decPointPos);
1081                         char* digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
1082
1083                         ResetCharBuf (size);
1084                         _ind = size;
1085                         ulong val = _val1 | ((ulong)_val2 << 32);
1086                         while (size > 0) {
1087                                 _cbuf [--size] = digits [val & 0xf];
1088                                 val >>= 4;
1089                         }
1090                         return new string (_cbuf, 0, _ind);
1091                 }
1092
1093                 string FormatFixedPoint (int precision, NumberFormatInfo nfi)
1094                 {
1095                         if (precision == -1)
1096                                 precision = nfi.NumberDecimalDigits;
1097
1098                         RoundDecimal (precision);
1099
1100                         ResetCharBuf (IntegerDigits + precision + 2);
1101
1102                         if (!_positive)
1103                                 Append (nfi.NegativeSign);
1104
1105                         AppendIntegerString (IntegerDigits);
1106
1107                         if (precision > 0) {
1108                                 Append (nfi.NumberDecimalSeparator);
1109                                 AppendDecimalString (precision);
1110                         }
1111
1112                         return new string (_cbuf, 0, _ind);
1113                 }
1114
1115                 private string FormatRoundtrip (double origval, NumberFormatInfo nfi)
1116                 {
1117                         NumberFormatter nfc = GetClone ();
1118                         if (origval >= MinRoundtripVal && origval <= MaxRoundtripVal) {
1119                                 string shortRep = FormatGeneral (_defPrecision, nfi);
1120                                 if (origval == Double.Parse (shortRep, nfi))
1121                                         return shortRep;
1122                         }
1123                         return nfc.FormatGeneral (_defPrecision + 2, nfi);
1124                 }
1125
1126                 private string FormatRoundtrip (float origval, NumberFormatInfo nfi)
1127                 {
1128                         NumberFormatter nfc = GetClone ();
1129                         string shortRep = FormatGeneral (_defPrecision, nfi);
1130                         // Check roundtrip only for "normal" double values.
1131                         if (origval == Single.Parse (shortRep, nfi))
1132                                 return shortRep;
1133                         return nfc.FormatGeneral (_defPrecision + 2, nfi);
1134                 }
1135
1136                 private string FormatGeneral (int precision, NumberFormatInfo nfi)
1137                 {
1138                         bool enableExp;
1139                         if (precision == -1) {
1140                                 enableExp = IsFloatingSource;
1141                                 precision = _defPrecision;
1142                         }
1143                         else {
1144                                 enableExp = true;
1145                                 if (precision == 0)
1146                                         precision = _defPrecision;
1147                                 RoundPos (precision);
1148                         }
1149
1150                         int intDigits = _decPointPos;
1151                         int digits = _digitsLen;
1152                         int decDigits = digits - intDigits;
1153
1154                         if ((intDigits > precision || intDigits <= -4) && enableExp)
1155                                 return FormatExponential (digits - 1, nfi, 2);
1156
1157                         if (decDigits < 0)
1158                                 decDigits = 0;
1159                         if (intDigits < 0)
1160                                 intDigits = 0;
1161                         ResetCharBuf (decDigits + intDigits + 3);
1162
1163                         if (!_positive)
1164                                 Append (nfi.NegativeSign);
1165
1166                         if (intDigits == 0)
1167                                 Append ('0');
1168                         else
1169                                 AppendDigits (digits - intDigits, digits);
1170
1171                         if (decDigits > 0) {
1172                                 Append (nfi.NumberDecimalSeparator);
1173                                 AppendDigits (0, decDigits);
1174                         }
1175
1176                         return new string (_cbuf, 0, _ind);
1177                 }
1178
1179                 string FormatNumber (int precision, NumberFormatInfo nfi)
1180                 {
1181                         precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
1182                         ResetCharBuf (IntegerDigits * 3 + precision);
1183                         RoundDecimal (precision);
1184
1185                         if (!_positive) {
1186                                 switch (nfi.NumberNegativePattern) {
1187                                 case 0:
1188                                         Append ('(');
1189                                         break;
1190                                 case 1:
1191                                         Append (nfi.NegativeSign);
1192                                         break;
1193                                 case 2:
1194                                         Append (nfi.NegativeSign);
1195                                         Append (' ');
1196                                         break;
1197                                 }
1198                         }
1199
1200                         AppendIntegerStringWithGroupSeparator (nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
1201
1202                         if (precision > 0) {
1203                                 Append (nfi.NumberDecimalSeparator);
1204                                 AppendDecimalString (precision);
1205                         }
1206
1207                         if (!_positive) {
1208                                 switch (nfi.NumberNegativePattern) {
1209                                 case 0:
1210                                         Append (')');
1211                                         break;
1212                                 case 3:
1213                                         Append (nfi.NegativeSign);
1214                                         break;
1215                                 case 4:
1216                                         Append (' ');
1217                                         Append (nfi.NegativeSign);
1218                                         break;
1219                                 }
1220                         }
1221
1222                         return new string (_cbuf, 0, _ind);
1223                 }
1224
1225                 string FormatPercent (int precision, NumberFormatInfo nfi)
1226                 {
1227                         precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
1228                         Multiply10(2);
1229                         RoundDecimal (precision);
1230                         ResetCharBuf (IntegerDigits * 2 + precision + 16);
1231
1232                         if (_positive) {
1233                                 if (nfi.PercentPositivePattern == 2)
1234                                         Append (nfi.PercentSymbol);
1235                         }
1236                         else {
1237                                 switch (nfi.PercentNegativePattern) {
1238                                 case 0:
1239                                         Append (nfi.NegativeSign);
1240                                         break;
1241                                 case 1:
1242                                         Append (nfi.NegativeSign);
1243                                         break;
1244                                 case 2:
1245                                         Append (nfi.NegativeSign);
1246                                         Append (nfi.PercentSymbol);
1247                                         break;
1248                                 }
1249                         }
1250
1251                         AppendIntegerStringWithGroupSeparator (nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
1252
1253                         if (precision > 0) {
1254                                 Append (nfi.PercentDecimalSeparator);
1255                                 AppendDecimalString (precision);
1256                         }
1257
1258                         if (_positive) {
1259                                 switch (nfi.PercentPositivePattern) {
1260                                 case 0:
1261                                         Append (' ');
1262                                         Append (nfi.PercentSymbol);
1263                                         break;
1264                                 case 1:
1265                                         Append (nfi.PercentSymbol);
1266                                         break;
1267                                 }
1268                         }
1269                         else {
1270                                 switch (nfi.PercentNegativePattern) {
1271                                 case 0:
1272                                         Append (' ');
1273                                         Append (nfi.PercentSymbol);
1274                                         break;
1275                                 case 1:
1276                                         Append (nfi.PercentSymbol);
1277                                         break;
1278                                 }
1279                         }
1280
1281                         return new string (_cbuf, 0, _ind);
1282                 }
1283
1284                  string FormatExponential (int precision, NumberFormatInfo nfi)
1285                 {
1286                         if (precision == -1)
1287                                 precision = DefaultExpPrecision;
1288
1289                         RoundPos (precision + 1);
1290                         return FormatExponential (precision, nfi, 3);
1291                 }
1292
1293                 private string FormatExponential (int precision, NumberFormatInfo nfi, int expDigits)
1294                 {
1295                         int decDigits = _decPointPos;
1296                         int digits = _digitsLen;
1297                         int exponent = decDigits - 1;
1298                         decDigits = _decPointPos = 1;
1299
1300                         ResetCharBuf (precision + 8);
1301
1302                         if (!_positive)
1303                                 Append (nfi.NegativeSign);
1304
1305                         AppendOneDigit (digits - 1);
1306
1307                         if (precision > 0) {
1308                                 Append (nfi.NumberDecimalSeparator);
1309                                 AppendDigits (digits - precision - 1, digits - _decPointPos);
1310                         }
1311
1312                         AppendExponent (nfi, exponent, expDigits);
1313
1314                         return new string (_cbuf, 0, _ind);
1315                 }
1316
1317                 string FormatCustom (string format, NumberFormatInfo nfi)
1318                 {
1319                         bool p = _positive;
1320                         int offset = 0;
1321                         int length = 0;
1322                         CustomInfo.GetActiveSection (format, ref p, IsZero, ref offset, ref length);
1323                         if (length == 0)
1324                                 return _positive ? string.Empty : nfi.NegativeSign;
1325                         _positive = p;
1326
1327                         CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
1328 #if false
1329                         Console.WriteLine ("Format : {0}",format);
1330                         Console.WriteLine ("DecimalDigits : {0}",info.DecimalDigits);
1331                         Console.WriteLine ("DecimalPointPos : {0}",info.DecimalPointPos);
1332                         Console.WriteLine ("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
1333                         Console.WriteLine ("IntegerDigits : {0}",info.IntegerDigits);
1334                         Console.WriteLine ("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
1335                         Console.WriteLine ("IntegerHeadPos : {0}",info.IntegerHeadPos);
1336                         Console.WriteLine ("UseExponent : {0}",info.UseExponent);
1337                         Console.WriteLine ("ExponentDigits : {0}",info.ExponentDigits);
1338                         Console.WriteLine ("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
1339                         Console.WriteLine ("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
1340                         Console.WriteLine ("DividePlaces : {0}",info.DividePlaces);
1341                         Console.WriteLine ("Percents : {0}",info.Percents);
1342                         Console.WriteLine ("Permilles : {0}",info.Permilles);
1343 #endif
1344                         StringBuilder sb_int = new StringBuilder (info.IntegerDigits * 2);
1345                         StringBuilder sb_dec = new StringBuilder (info.DecimalDigits * 2);
1346                         StringBuilder sb_exp = (info.UseExponent ? new StringBuilder (info.ExponentDigits * 2) : null);
1347
1348                         int diff = 0;
1349                         if (info.Percents > 0)
1350                                 Multiply10(2 * info.Percents);
1351                         if (info.Permilles > 0)
1352                                 Multiply10(3 * info.Permilles);
1353                         if (info.DividePlaces > 0)
1354                                 Divide10(info.DividePlaces);
1355
1356                         bool expPositive = true;
1357                         if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
1358                                 if (!IsZero) {
1359                                         RoundPos (info.DecimalDigits + info.IntegerDigits);
1360                                         diff -= _decPointPos - info.IntegerDigits;
1361                                         _decPointPos = info.IntegerDigits;
1362                                 }
1363
1364                                 expPositive = diff <= 0;
1365                                 AppendNonNegativeNumber (sb_exp, diff < 0 ? -diff : diff);
1366                         }
1367                         else
1368                                 RoundDecimal (info.DecimalDigits);
1369
1370                         if (info.IntegerDigits != 0 || !IsZeroInteger)
1371                                 AppendIntegerString (IntegerDigits, sb_int);
1372
1373                         AppendDecimalString (DecimalDigits, sb_dec);
1374
1375                         if (info.UseExponent) {
1376                                 if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
1377                                         _positive = true;
1378
1379                                 if (sb_int.Length < info.IntegerDigits)
1380                                         sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
1381
1382                                 while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
1383                                         sb_exp.Insert (0, '0');
1384
1385                                 if (expPositive && !info.ExponentNegativeSignOnly)
1386                                         sb_exp.Insert (0, nfi.PositiveSign);
1387                                 else if (!expPositive)
1388                                         sb_exp.Insert (0, nfi.NegativeSign);
1389                         }
1390                         else {
1391                                 if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
1392                                         sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
1393                                 if (info.IntegerDigits == info.IntegerHeadSharpDigits && IsZeroOnly (sb_int))
1394                                         sb_int.Remove (0, sb_int.Length);
1395                         }
1396
1397                         ZeroTrimEnd (sb_dec, true);
1398                         while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
1399                                 sb_dec.Append ('0');
1400                         if (sb_dec.Length > info.DecimalDigits)
1401                                 sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
1402
1403                         return info.Format (format, offset, length, nfi, _positive, sb_int, sb_dec, sb_exp);
1404                 }
1405                 #endregion public number formatting methods
1406
1407                 #region StringBuilder formatting helpers
1408
1409                 private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
1410                 {
1411                         int len = 0;
1412                         for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i--) {
1413                                 if (sb [i] != '0')
1414                                         break;
1415                                 len++;
1416                         }
1417
1418                         if (len > 0)
1419                                 sb.Remove (sb.Length - len, len);
1420                 }
1421
1422                 private static bool IsZeroOnly (StringBuilder sb)
1423                 {
1424                         for (int i = 0; i < sb.Length; i++)
1425                                 if (char.IsDigit (sb [i]) && sb [i] != '0')
1426                                         return false;
1427                         return true;
1428                 }
1429
1430                 private static void AppendNonNegativeNumber (StringBuilder sb, int v)
1431                 {
1432                         if (v < 0)
1433                                 throw new ArgumentException ();
1434
1435                         int i = ScaleOrder (v) - 1;
1436                         do {
1437                                 int n = v / (int)GetTenPowerOf (i);
1438                                 sb.Append ((char)('0' | n));
1439                                 v -= (int)GetTenPowerOf (i--) * n;
1440                         } while (i >= 0);
1441                 }
1442
1443                 #endregion StringBuilder formatting helpers
1444
1445                 #region Append helpers
1446
1447                 private void AppendIntegerString (int minLength, StringBuilder sb)
1448                 {
1449                         if (_decPointPos <= 0) {
1450                                 sb.Append ('0', minLength);
1451                                 return;
1452                         }
1453
1454                         if (_decPointPos < minLength)
1455                                 sb.Append ('0', minLength - _decPointPos);
1456
1457                         AppendDigits (_digitsLen - _decPointPos, _digitsLen, sb);
1458                 }
1459
1460                 private void AppendIntegerString (int minLength)
1461                 {
1462                         if (_decPointPos <= 0) {
1463                                 Append ('0', minLength);
1464                                 return;
1465                         }
1466
1467                         if (_decPointPos < minLength)
1468                                 Append ('0', minLength - _decPointPos);
1469
1470                         AppendDigits (_digitsLen - _decPointPos, _digitsLen);
1471                 }
1472
1473                 private void AppendDecimalString (int precision, StringBuilder sb)
1474                 {
1475                         AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos, sb);
1476                 }
1477
1478                 private void AppendDecimalString (int precision)
1479                 {
1480                         AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos);
1481                 }
1482
1483                 private void AppendIntegerStringWithGroupSeparator (int[] groups, string groupSeparator)
1484                 {
1485                         if (IsZeroInteger) {
1486                                 Append ('0');
1487                                 return;
1488                         }
1489
1490                         int total = 0;
1491                         int groupIndex = 0;
1492                         for (int i = 0; i < groups.Length; i++) {
1493                                 total += groups [i];
1494                                 if (total <= _decPointPos)
1495                                         groupIndex = i;
1496                                 else
1497                                         break;
1498                         }
1499
1500                         if (groups.Length > 0 && total > 0) {
1501                                 int counter;
1502                                 int groupSize = groups [groupIndex];
1503                                 int fraction = _decPointPos > total ? _decPointPos - total : 0;
1504                                 if (groupSize == 0) {
1505                                         while (groupIndex >= 0 && groups [groupIndex] == 0)
1506                                                 groupIndex--;
1507
1508                                         groupSize = fraction > 0 ? fraction : groups [groupIndex];
1509                                 }
1510                                 if (fraction == 0)
1511                                         counter = groupSize;
1512                                 else {
1513                                         groupIndex += fraction / groupSize;
1514                                         counter = fraction % groupSize;
1515                                         if (counter == 0)
1516                                                 counter = groupSize;
1517                                         else
1518                                                 groupIndex++;
1519                                 }
1520
1521                                 if (total >= _decPointPos) {
1522                                         int lastGroupSize = groups [0];
1523                                         if (total > lastGroupSize) {
1524                                                 int lastGroupDiff = -(lastGroupSize - _decPointPos);
1525                                                 int lastGroupMod;
1526
1527                                                 if (lastGroupDiff < lastGroupSize)
1528                                                         counter = lastGroupDiff;
1529                                                 else if (lastGroupSize > 0 && (lastGroupMod = _decPointPos % lastGroupSize) > 0)
1530                                                         counter = lastGroupMod;
1531                                         }
1532                                 }
1533                                 
1534                                 for (int i = 0; ;) {
1535                                         if ((_decPointPos - i) <= counter || counter == 0) {
1536                                                 AppendDigits (_digitsLen - _decPointPos, _digitsLen - i);
1537                                                 break;
1538                                         }
1539                                         AppendDigits (_digitsLen - i - counter, _digitsLen - i);
1540                                         i += counter;
1541                                         Append (groupSeparator);
1542                                         if (--groupIndex < groups.Length && groupIndex >= 0)
1543                                                 groupSize = groups [groupIndex];
1544                                         counter = groupSize;
1545                                 }
1546                         }
1547                         else {
1548                                 AppendDigits (_digitsLen - _decPointPos, _digitsLen);
1549                         }
1550                 }
1551
1552                 // minDigits is in the range 1..3
1553                 private void AppendExponent (NumberFormatInfo nfi, int exponent, int minDigits)
1554                 {
1555                         if (_specifierIsUpper || _specifier == 'R')
1556                                 Append ('E');
1557                         else
1558                                 Append ('e');
1559
1560                         if (exponent >= 0)
1561                                 Append (nfi.PositiveSign);
1562                         else {
1563                                 Append (nfi.NegativeSign);
1564                                 exponent = -exponent;
1565                         }
1566
1567                         if (exponent == 0)
1568                                 Append ('0', minDigits);
1569                         else if (exponent < 10) {
1570                                 Append ('0', minDigits - 1);
1571                                 Append ((char)('0' | exponent));
1572                         }
1573                         else {
1574                                 uint hexDigit = FastToDecHex (exponent);
1575                                 if (exponent >= 100 || minDigits == 3)
1576                                         Append ((char)('0' | (hexDigit >> 8)));
1577                                 Append ((char)('0' | ((hexDigit >> 4) & 0xf)));
1578                                 Append ((char)('0' | (hexDigit & 0xf)));
1579                         }
1580                 }
1581
1582                 private void AppendOneDigit (int start)
1583                 {
1584                         if (_ind == _cbuf.Length)
1585                                 Resize (_ind + 10);
1586
1587                         start += _offset;
1588                         uint v;
1589                         if (start < 0)
1590                                 v = 0;
1591                         else if (start < 8)
1592                                 v = _val1;
1593                         else if (start < 16)
1594                                 v = _val2;
1595                         else if (start < 24)
1596                                 v = _val3;
1597                         else if (start < 32)
1598                                 v = _val4;
1599                         else
1600                                 v = 0;
1601                         v >>= (start & 0x7) << 2;
1602                         _cbuf [_ind++] = (char)('0' | v & 0xf);
1603                 }
1604
1605                 private void AppendDigits (int start, int end)
1606                 {
1607                         if (start >= end)
1608                                 return;
1609
1610                         int i = _ind + (end - start);
1611                         if (i > _cbuf.Length)
1612                                 Resize (i + 10);
1613                         _ind = i;
1614
1615                         end += _offset;
1616                         start += _offset;
1617
1618                         for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
1619                                 uint v;
1620                                 if (next == 8)
1621                                         v = _val1;
1622                                 else if (next == 16)
1623                                         v = _val2;
1624                                 else if (next == 24)
1625                                         v = _val3;
1626                                 else if (next == 32)
1627                                         v = _val4;
1628                                 else
1629                                         v = 0;
1630                                 v >>= (start & 0x7) << 2;
1631                                 if (next > end)
1632                                         next = end;
1633
1634                                 _cbuf [--i] = (char)('0' | v & 0xf);
1635                                 switch (next - start) {
1636                                 case 8:
1637                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1638                                         goto case 7;
1639                                 case 7:
1640                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1641                                         goto case 6;
1642                                 case 6:
1643                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1644                                         goto case 5;
1645                                 case 5:
1646                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1647                                         goto case 4;
1648                                 case 4:
1649                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1650                                         goto case 3;
1651                                 case 3:
1652                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1653                                         goto case 2;
1654                                 case 2:
1655                                         _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
1656                                         goto case 1;
1657                                 case 1:
1658                                         if (next == end)
1659                                                 return;
1660                                         continue;
1661                                 }
1662                         }
1663                 }
1664
1665                 private void AppendDigits (int start, int end, StringBuilder sb)
1666                 {
1667                         if (start >= end)
1668                                 return;
1669
1670                         int i = sb.Length + (end - start);
1671                         sb.Length = i;
1672
1673                         end += _offset;
1674                         start += _offset;
1675
1676                         for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
1677                                 uint v;
1678                                 if (next == 8)
1679                                         v = _val1;
1680                                 else if (next == 16)
1681                                         v = _val2;
1682                                 else if (next == 24)
1683                                         v = _val3;
1684                                 else if (next == 32)
1685                                         v = _val4;
1686                                 else
1687                                         v = 0;
1688                                 v >>= (start & 0x7) << 2;
1689                                 if (next > end)
1690                                         next = end;
1691                                 sb [--i] = (char)('0' | v & 0xf);
1692                                 switch (next - start) {
1693                                 case 8:
1694                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1695                                         goto case 7;
1696                                 case 7:
1697                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1698                                         goto case 6;
1699                                 case 6:
1700                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1701                                         goto case 5;
1702                                 case 5:
1703                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1704                                         goto case 4;
1705                                 case 4:
1706                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1707                                         goto case 3;
1708                                 case 3:
1709                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1710                                         goto case 2;
1711                                 case 2:
1712                                         sb [--i] = (char)('0' | (v >>= 4) & 0xf);
1713                                         goto case 1;
1714                                 case 1:
1715                                         if (next == end)
1716                                                 return;
1717                                         continue;
1718                                 }
1719                         }
1720                 }
1721
1722                 #endregion Append helpers
1723
1724                 #region others
1725
1726                 private void Multiply10(int count)
1727                 {
1728                         if (count <= 0 || _digitsLen == 0)
1729                                 return;
1730
1731                         _decPointPos += count;
1732                 }
1733
1734                 private void Divide10(int count)
1735                 {
1736                         if (count <= 0 || _digitsLen == 0)
1737                                 return;
1738
1739                         _decPointPos -= count;
1740                 }
1741
1742                 private NumberFormatter GetClone ()
1743                 {
1744                         return (NumberFormatter)this.MemberwiseClone ();
1745                 }
1746
1747                 #endregion others
1748
1749                 #region custom
1750
1751                 private class CustomInfo
1752                 {
1753                         public bool UseGroup = false;
1754                         public int DecimalDigits = 0;
1755                         public int DecimalPointPos = -1;
1756                         public int DecimalTailSharpDigits = 0;
1757                         public int IntegerDigits = 0;
1758                         public int IntegerHeadSharpDigits = 0;
1759                         public int IntegerHeadPos = 0;
1760                         public bool UseExponent = false;
1761                         public int ExponentDigits = 0;
1762                         public int ExponentTailSharpDigits = 0;
1763                         public bool ExponentNegativeSignOnly = true;
1764                         public int DividePlaces = 0;
1765                         public int Percents = 0;
1766                         public int Permilles = 0;
1767
1768                         public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
1769                         {
1770                                 int[] lens = new int [3];
1771                                 int index = 0;
1772                                 int lastPos = 0;
1773                                 bool quoted = false;
1774
1775                                 for (int i = 0; i < format.Length; i++) {
1776                                         char c = format [i];
1777
1778                                         if (c == '\"' || c == '\'') {
1779                                                 if (i == 0 || format [i - 1] != '\\')
1780                                                         quoted = !quoted;
1781
1782                                                 continue;
1783                                         }
1784
1785                                         if (c == ';' && !quoted && (i == 0 || format [i - 1] != '\\')) {
1786                                                 lens [index++] = i - lastPos;
1787                                                 lastPos = i + 1;
1788                                                 if (index == 3)
1789                                                         break;
1790                                         }
1791                                 }
1792
1793                                 if (index == 0) {
1794                                         offset = 0;
1795                                         length = format.Length;
1796                                         return;
1797                                 }
1798                                 if (index == 1) {
1799                                         if (positive || zero) {
1800                                                 offset = 0;
1801                                                 length = lens [0];
1802                                                 return;
1803                                         }
1804                                         if (lens [0] + 1 < format.Length) {
1805                                                 positive = true;
1806                                                 offset = lens [0] + 1;
1807                                                 length = format.Length - offset;
1808                                                 return;
1809                                         }
1810                                         else {
1811                                                 offset = 0;
1812                                                 length = lens [0];
1813                                                 return;
1814                                         }
1815                                 }
1816                                 if (index == 2) {
1817                                         if (zero) {
1818                                                 offset = lens [0] + lens [1] + 2;
1819                                                 length = format.Length - offset;
1820                                                 return;
1821                                         }
1822                                         if (positive) {
1823                                                 offset = 0;
1824                                                 length = lens [0];
1825                                                 return;
1826                                         }
1827                                         if (lens [1] > 0) {
1828                                                 positive = true;
1829                                                 offset = lens [0] + 1;
1830                                                 length = lens [1];
1831                                                 return;
1832                                         }
1833                                         else {
1834                                                 offset = 0;
1835                                                 length = lens [0];
1836                                                 return;
1837                                         }
1838                                 }
1839                                 if (index == 3) {
1840                                         if (zero) {
1841                                                 offset = lens [0] + lens [1] + 2;
1842                                                 length = lens [2];
1843                                                 return;
1844                                         }
1845                                         if (positive) {
1846                                                 offset = 0;
1847                                                 length = lens [0];
1848                                                 return;
1849                                         }
1850                                         if (lens [1] > 0) {
1851                                                 positive = true;
1852                                                 offset = lens [0] + 1;
1853                                                 length = lens [1];
1854                                                 return;
1855                                         }
1856                                         else {
1857                                                 offset = 0;
1858                                                 length = lens [0];
1859                                                 return;
1860                                         }
1861                                 }
1862
1863                                 throw new ArgumentException ();
1864                         }
1865
1866                         public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
1867                         {
1868                                 char literal = '\0';
1869                                 bool integerArea = true;
1870                                 bool decimalArea = false;
1871                                 bool exponentArea = false;
1872                                 bool sharpContinues = true;
1873
1874                                 CustomInfo info = new CustomInfo ();
1875                                 int groupSeparatorCounter = 0;
1876
1877                                 for (int i = offset; i - offset < length; i++) {
1878                                         char c = format [i];
1879
1880                                         if (c == literal && c != '\0') {
1881                                                 literal = '\0';
1882                                                 continue;
1883                                         }
1884                                         if (literal != '\0')
1885                                                 continue;
1886
1887                                         if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
1888                                                 exponentArea = false;
1889                                                 integerArea = (info.DecimalPointPos < 0);
1890                                                 decimalArea = !integerArea;
1891                                                 i--;
1892                                                 continue;
1893                                         }
1894
1895                                         switch (c) {
1896                                         case '\\':
1897                                                 i++;
1898                                                 continue;
1899                                         case '\'':
1900                                         case '\"':
1901                                                 if (c == '\"' || c == '\'') {
1902                                                         literal = c;
1903                                                 }
1904                                                 continue;
1905                                         case '#':
1906                                                 if (sharpContinues && integerArea)
1907                                                         info.IntegerHeadSharpDigits++;
1908                                                 else if (decimalArea)
1909                                                         info.DecimalTailSharpDigits++;
1910                                                 else if (exponentArea)
1911                                                         info.ExponentTailSharpDigits++;
1912
1913                                                 goto case '0';
1914                                         case '0':
1915                                                 if (c != '#') {
1916                                                         sharpContinues = false;
1917                                                         if (decimalArea)
1918                                                                 info.DecimalTailSharpDigits = 0;
1919                                                         else if (exponentArea)
1920                                                                 info.ExponentTailSharpDigits = 0;
1921                                                 }
1922                                                 if (info.IntegerHeadPos == -1)
1923                                                         info.IntegerHeadPos = i;
1924
1925                                                 if (integerArea) {
1926                                                         info.IntegerDigits++;
1927                                                         if (groupSeparatorCounter > 0)
1928                                                                 info.UseGroup = true;
1929                                                         groupSeparatorCounter = 0;
1930                                                 }
1931                                                 else if (decimalArea)
1932                                                         info.DecimalDigits++;
1933                                                 else if (exponentArea)
1934                                                         info.ExponentDigits++;
1935                                                 break;
1936                                         case 'e':
1937                                         case 'E':
1938                                                 if (info.UseExponent)
1939                                                         break;
1940
1941                                                 info.UseExponent = true;
1942                                                 integerArea = false;
1943                                                 decimalArea = false;
1944                                                 exponentArea = true;
1945                                                 if (i + 1 - offset < length) {
1946                                                         char nc = format [i + 1];
1947                                                         if (nc == '+')
1948                                                                 info.ExponentNegativeSignOnly = false;
1949                                                         if (nc == '+' || nc == '-')
1950                                                                 i++;
1951                                                         else if (nc != '0' && nc != '#') {
1952                                                                 info.UseExponent = false;
1953                                                                 if (info.DecimalPointPos < 0)
1954                                                                         integerArea = true;
1955                                                         }
1956                                                 }
1957
1958                                                 break;
1959                                         case '.':
1960                                                 integerArea = false;
1961                                                 decimalArea = true;
1962                                                 exponentArea = false;
1963                                                 if (info.DecimalPointPos == -1)
1964                                                         info.DecimalPointPos = i;
1965                                                 break;
1966                                         case '%':
1967                                                 info.Percents++;
1968                                                 break;
1969                                         case '\u2030':
1970                                                 info.Permilles++;
1971                                                 break;
1972                                         case ',':
1973                                                 if (integerArea && info.IntegerDigits > 0)
1974                                                         groupSeparatorCounter++;
1975                                                 break;
1976                                         default:
1977                                                 break;
1978                                         }
1979                                 }
1980
1981                                 if (info.ExponentDigits == 0)
1982                                         info.UseExponent = false;
1983                                 else
1984                                         info.IntegerHeadSharpDigits = 0;
1985
1986                                 if (info.DecimalDigits == 0)
1987                                         info.DecimalPointPos = -1;
1988
1989                                 info.DividePlaces += groupSeparatorCounter * 3;
1990
1991                                 return info;
1992                         }
1993
1994                         public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
1995                         {
1996                                 StringBuilder sb = new StringBuilder ();
1997                                 char literal = '\0';
1998                                 bool integerArea = true;
1999                                 bool decimalArea = false;
2000                                 int intSharpCounter = 0;
2001                                 int sb_int_index = 0;
2002                                 int sb_dec_index = 0;
2003
2004                                 int[] groups = nfi.NumberGroupSizes;
2005                                 string groupSeparator = nfi.NumberGroupSeparator;
2006                                 int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0;
2007                                 if (UseGroup && groups.Length > 0) {
2008                                         intLen = sb_int.Length;
2009                                         for (int i = 0; i < groups.Length; i++) {
2010                                                 total += groups [i];
2011                                                 if (total <= intLen)
2012                                                         groupIndex = i;
2013                                         }
2014                                         groupSize = groups [groupIndex];
2015                                         int fraction = intLen > total ? intLen - total : 0;
2016                                         if (groupSize == 0) {
2017                                                 while (groupIndex >= 0 && groups [groupIndex] == 0)
2018                                                         groupIndex--;
2019
2020                                                 groupSize = fraction > 0 ? fraction : groups [groupIndex];
2021                                         }
2022                                         if (fraction == 0)
2023                                                 counter = groupSize;
2024                                         else {
2025                                                 groupIndex += fraction / groupSize;
2026                                                 counter = fraction % groupSize;
2027                                                 if (counter == 0)
2028                                                         counter = groupSize;
2029                                                 else
2030                                                         groupIndex++;
2031                                         }
2032                                 }
2033                                 else
2034                                         UseGroup = false;
2035
2036                                 for (int i = offset; i - offset < length; i++) {
2037                                         char c = format [i];
2038
2039                                         if (c == literal && c != '\0') {
2040                                                 literal = '\0';
2041                                                 continue;
2042                                         }
2043                                         if (literal != '\0') {
2044                                                 sb.Append (c);
2045                                                 continue;
2046                                         }
2047
2048                                         switch (c) {
2049                                         case '\\':
2050                                                 i++;
2051                                                 if (i - offset < length)
2052                                                         sb.Append (format [i]);
2053                                                 continue;
2054                                         case '\'':
2055                                         case '\"':
2056                                                 if (c == '\"' || c == '\'')
2057                                                         literal = c;
2058                                                 continue;
2059                                         case '#':
2060                                                 goto case '0';
2061                                         case '0':
2062                                                 if (integerArea) {
2063                                                         intSharpCounter++;
2064                                                         if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
2065                                                                 while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
2066                                                                         sb.Append (sb_int [sb_int_index++]);
2067                                                                         if (UseGroup && --intLen > 0 && --counter == 0) {
2068                                                                                 sb.Append (groupSeparator);
2069                                                                                 if (--groupIndex < groups.Length && groupIndex >= 0)
2070                                                                                         groupSize = groups [groupIndex];
2071                                                                                 counter = groupSize;
2072                                                                         }
2073                                                                 }
2074                                                         break;
2075                                                 }
2076                                                 else if (decimalArea) {
2077                                                         if (sb_dec_index < sb_dec.Length)
2078                                                                 sb.Append (sb_dec [sb_dec_index++]);
2079                                                         break;
2080                                                 }
2081
2082                                                 sb.Append (c);
2083                                                 break;
2084                                         case 'e':
2085                                         case 'E':
2086                                                 if (sb_exp == null || !UseExponent) {
2087                                                         sb.Append (c);
2088                                                         break;
2089                                                 }
2090
2091                                                 bool flag1 = true;
2092                                                 bool flag2 = false;
2093
2094                                                 int q;
2095                                                 for (q = i + 1; q - offset < length; q++) {
2096                                                         if (format [q] == '0') {
2097                                                                 flag2 = true;
2098                                                                 continue;
2099                                                         }
2100                                                         if (q == i + 1 && (format [q] == '+' || format [q] == '-'))
2101                                                                 continue;
2102                                                         if (!flag2)
2103                                                                 flag1 = false;
2104                                                         break;
2105                                                 }
2106
2107                                                 if (flag1) {
2108                                                         i = q - 1;
2109                                                         integerArea = (DecimalPointPos < 0);
2110                                                         decimalArea = !integerArea;
2111
2112                                                         sb.Append (c);
2113                                                         sb.Append (sb_exp);
2114                                                         sb_exp = null;
2115                                                 }
2116                                                 else
2117                                                         sb.Append (c);
2118
2119                                                 break;
2120                                         case '.':
2121                                                 if (DecimalPointPos == i) {
2122                                                         if (DecimalDigits > 0) {
2123                                                                 while (sb_int_index < sb_int.Length)
2124                                                                         sb.Append (sb_int [sb_int_index++]);
2125                                                         }
2126                                                         if (sb_dec.Length > 0)
2127                                                                 sb.Append (nfi.NumberDecimalSeparator);
2128                                                 }
2129                                                 integerArea = false;
2130                                                 decimalArea = true;
2131                                                 break;
2132                                         case ',':
2133                                                 break;
2134                                         case '%':
2135                                                 sb.Append (nfi.PercentSymbol);
2136                                                 break;
2137                                         case '\u2030':
2138                                                 sb.Append (nfi.PerMilleSymbol);
2139                                                 break;
2140                                         default:
2141                                                 sb.Append (c);
2142                                                 break;
2143                                         }
2144                                 }
2145
2146                                 if (!positive)
2147                                         sb.Insert (0, nfi.NegativeSign);
2148
2149                                 return sb.ToString ();
2150                         }
2151                 }
2152
2153                 #endregion
2154         }
2155 }