Merge branch 'master' into msbuilddll2
[mono.git] / mcs / class / corlib / System / NumberFormatter.cs
index 4ff029cd761cf6be98651b960ba07c9b7dd129e5..dc0fb5a1e11800578f51294235ee4d2d5884cb05 100644 (file)
 //
 // Author:
 //   Kazuki Oikawa (kazuki@panicode.com)
+//   Eyal Alaluf (eyala@mainsoft.com)
 //
+// Copyright (C) 2004 Novell, Inc (http://www.novell.com)
+// Copyright (C) 2008 Mainsoft Co. (http://www.mainsoft.com)
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+// 
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+// 
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+// NumberFormatter is shared with Grasshopper and hence the #if TARGET_JVM for
+// marking the use of unsafe code that is not supported in Grasshopper.
+#if !TARGET_JVM
+#define UNSAFE_TABLES
+#endif
 
-using System.Collections;
 using System.Globalization;
 using System.Text;
+using System.Threading;
+using System.Runtime.CompilerServices;
 
 namespace System
 {
-       class NumberFormatter
+       internal sealed partial class NumberFormatter
        {
-               static char[] digitLowerTable = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
-               static char[] digitUpperTable = {'0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F'};
-
-               #region NumberToString
-               public static string NumberToString (string format, sbyte value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 1, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, byte value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value, true, 1, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, ushort value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value, true, 2, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, short value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 2, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, uint value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value, true, 4, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, int value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-(long)value, value >= 0, 4, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, ulong value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value, true, 8, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, long value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X'))
-                               return FormatHexadecimal (value >= 0 ? (ulong)value : (ulong)-value, value >= 0, 8, precision, specifier == 'X');
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, float value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, double value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, decimal value, NumberFormatInfo nfi)
-               {
-                       char specifier;
-                       int precision;
-                       bool custom;
-                       ParseBasicFormat (format, out specifier, out precision, out custom);
-                       if (!custom && (specifier == 'x' || specifier == 'X')) throw new FormatException ();
-                       return NumberToString (format, new NumberStore (value), nfi, specifier, precision, custom);
-               }
-               public static string NumberToString (string format, NumberStore ns, NumberFormatInfo nfi, char specifier, int precision, bool custom)
-               {
-                       if (ns.IsNaN) {
-                               return nfi.NaNSymbol;
-                       }
-                       if (ns.IsInfinity) {
-                               if (ns.Positive)
-                                       return nfi.PositiveInfinitySymbol;
-                               else
-                                       return nfi.NegativeInfinitySymbol;
-                       }
-
-                       if (nfi == null) 
-                               nfi = NumberFormatInfo.GetInstance (null);
-                       
-                       if (custom){
-                               if (ns.IsFloatingSource)
-                                       ns.RoundEffectiveDigits (ns.DefaultPrecision);
-                               return FormatCustom (format, ns, nfi);
-                       }
-
-                       if (ns.IsFloatingSource) {
-                               switch(specifier) {
-                               case 'p':
-                               case 'P':
-                               case 'c':
-                               case 'C':
-                               case 'f':
-                               case 'F':
-                               case 'N':
-                               case 'n':
-                                       ns.RoundEffectiveDigits (ns.DefaultPrecision);
-                                       break;
-                               case 'g':
-                               case 'G':
-                                       if (precision <= 0)
-                                               ns.RoundEffectiveDigits (ns.DefaultPrecision, ns.IsBankerApplicable, true);
-                                       else
-                                               ns.RoundEffectiveDigits (precision);
-                                       break;
-                               case 'r':
-                               case 'R':
-                                       ns.RoundEffectiveDigits (ns.DefaultMaxPrecision);
-                                       break;
-                               default:
-                                       if (precision > ns.DefaultPrecision)
-                                               ns.RoundEffectiveDigits (precision + 1);
-                                       else
-                                               ns.RoundEffectiveDigits (ns.DefaultPrecision + 1);
-                                       break;
-                               }
-                       }
-
-                       switch(specifier) {
-                       case 'c':
-                       case 'C':
-                               return FormatCurrency (ns, precision, nfi);
-                       case 'd':
-                       case 'D':
-                               return FormatDecimal (ns, precision, nfi);
-                       case 'e':
-                       case 'E':
-                               return FormatExponential (ns, precision, nfi, specifier == 'E');
-                       case 'f': 
-                       case 'F':
-                               return FormatFixedPoint (ns, precision, nfi);
-                       case 'g':
-                       case 'G':
-                               if (ns.IsFloatingSource || ns.IsDecimalSource || precision != -1)
-                                       return FormatGeneral (ns, precision, nfi, specifier == 'G', false);
-                               return FormatDecimal (ns, precision, nfi);
-                       case 'n':
-                       case 'N':
-                               return FormatNumber (ns, precision, nfi);
-                       case 'p':
-                       case 'P':
-                               return FormatPercent (ns, precision, nfi);
-                       case 'r':
-                       case 'R':
-                               if (ns.IsFloatingSource) {
-                                       return FormatGeneral (ns, ns.DefaultPrecision, nfi, true, true);
-                               } else {
-                                       throw new FormatException (Locale.GetText ("The specified format cannot be used in this instance"));
-                               }
-                       default: 
-                               throw new FormatException (Locale.GetText ("The specified format '" + format + "' is invalid"));
-                       }       
+               #region Static Fields
+
+               const int DefaultExpPrecision = 6;
+               const int HundredMillion = 100000000;
+               const long SeventeenDigitsThreshold = 10000000000000000;
+               const ulong ULongDivHundredMillion = UInt64.MaxValue / HundredMillion;
+               const ulong ULongModHundredMillion = 1 + UInt64.MaxValue % HundredMillion;
+
+               const int DoubleBitsExponentShift = 52;
+               const int DoubleBitsExponentMask = 0x7ff;
+               const long DoubleBitsMantissaMask = 0xfffffffffffff;
+               const int DecimalBitsScaleMask = 0x1f0000;
+
+               const int SingleDefPrecision = 7;
+               const int DoubleDefPrecision = 15;
+               const int Int8DefPrecision = 3;
+               const int UInt8DefPrecision = 3;
+               const int Int16DefPrecision = 5;
+               const int UInt16DefPrecision = 5;
+               const int Int32DefPrecision = 10;
+               const int UInt32DefPrecision = 10;
+               const int Int64DefPrecision = 19;
+               const int UInt64DefPrecision = 20;
+               const int DecimalDefPrecision = 100;
+               const int TenPowersListLength = 19;
+
+               const double MinRoundtripVal = -1.79769313486231E+308;
+               const double MaxRoundtripVal = 1.79769313486231E+308;
+
+#if UNSAFE_TABLES
+               // The below arrays are taken from mono/metatdata/number-formatter.h
+
+               private static readonly unsafe ulong* MantissaBitsTable;
+               private static readonly unsafe int* TensExponentTable;
+               private static readonly unsafe char* DigitLowerTable;
+               private static readonly unsafe char* DigitUpperTable;
+               private static readonly unsafe long* TenPowersList;
+
+               // DecHexDigits s a translation table from a decimal number to its
+               // digits hexadecimal representation (e.g. DecHexDigits [34] = 0x34).
+               private static readonly unsafe int* DecHexDigits;
+
+               [MethodImplAttribute(System.Runtime.CompilerServices.MethodImplOptions.InternalCall)]
+               private unsafe static extern void GetFormatterTables (out ulong* MantissaBitsTable, out int* TensExponentTable,
+                               out char* DigitLowerTable, out char* DigitUpperTable,
+                               out long* TenPowersList, out int* DecHexDigits);
+
+               unsafe static NumberFormatter()
+               {
+                       GetFormatterTables (out MantissaBitsTable, out TensExponentTable,
+                               out DigitLowerTable, out DigitUpperTable, out TenPowersList, out DecHexDigits);
                }
-               #endregion
 
-               #region BasicParser
-               private static void ParseBasicFormat (string format, out char specifier, out int precision, out bool custom)
+               unsafe
+#endif
+               static long GetTenPowerOf(int i)
                {
-                       if (format == null || format.Length == 0) {
-                               precision = -1;
-                               specifier = 'G';
-                               custom = false;
-                               return;
-                       }
+                       return TenPowersList [i];
+               }
+               #endregion Static Fields
 
-                       precision = -1;
-                       specifier = format[0];
-                       custom = false;
+               #region Fields
 
-                       if (Char.IsLetter (specifier)) {
-                               if (format.Length == 1)
-                                       return;
+               private NumberFormatInfo _nfi;
 
-                               bool flag = true;
-                               precision = 0;
-                               for (int i = 1; i < format.Length; i++) {
-                                       char c = format [i];
-                                       if (char.IsDigit (c)) {
-                                               precision = precision * 10 + (c - '0');
-                                               if (precision > 99) {
-                                                       flag = false;
-                                                       break;
-                                               }
-                                       }
-                                       else {
-                                               flag = false;
-                                               break;
-                                       }
-                               }
-                               if (flag)
-                                       return;
-                       }
+               //part of the private stringbuffer
+               private char[] _cbuf;
 
-                       custom = true;
-                       return;
-               }       
+               private bool _NaN;
+               private bool _infinity;
+               private bool _isCustomFormat;
+               private bool _specifierIsUpper;
+               private bool _positive;
+               private char _specifier;
+               private int _precision;
+               private int _defPrecision;
 
-               #endregion
+               private int _digitsLen;
+               private int _offset; // Represent the first digit offset.
+               private int _decPointPos;
 
-               #region Helpers
-               private static void ZeroTrimEnd (StringBuilder sb)
-               {
-                       ZeroTrimEnd (sb, false);
-               }
-               private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
-               {
-                       int len = 0;
-                       for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i --) {
-                               if (sb [i] != '0')
-                                       break;
-                               len ++;
-                       }
+               // The following fields are a hexadeimal representation of the digits.
+               // For instance _val = 0x234 represents the digits '2', '3', '4'.
+               private uint _val1; // Digits 0 - 7.
+               private uint _val2; // Digits 8 - 15.
+               private uint _val3; // Digits 16 - 23.
+               private uint _val4; // Digits 23 - 31. Only needed for decimals.
 
-                       if (len > 0)
-                               sb.Remove (sb.Length - len, len);
-               }
-               #endregion
+               #endregion Fields
 
-               #region Basic
-               internal static string FormatCurrency (NumberStore ns, int precision, NumberFormatInfo nfi)
-               {
-                       precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
-                       ns.RoundDecimal (precision);
-                       StringBuilder sb = new StringBuilder (ns.IntegerDigits * 2 + precision * 2 + 16);
-                       bool needNegativeSign = !ns.Positive && !ns.ZeroOnly;
+               #region Constructor Helpers
 
-                       if (!needNegativeSign) {
-                               switch (nfi.CurrencyPositivePattern) {
-                               case 0:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 2:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (' ');
-                                       break;
-                               }
-                       } else {
-                               switch (nfi.CurrencyNegativePattern) {
-                               case 0:
-                                       sb.Append ('(');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 1:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 2:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 3:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 4:
-                                       sb.Append ('(');
-                                       break;
-                               case 5:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 8:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 9:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (' ');                                        
-                                       break;
-                               case 11:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (' ');
-                                       break;
-                               case 12:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (' ');
-                                       sb.Append (nfi.NegativeSign);                                   
-                                       break;
-                               case 14:
-                                       sb.Append ('(');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (' ');
-                                       break;
-                               case 15:
-                                       sb.Append ('(');
-                                       break;
-                               }
+               // Translate an unsigned int to hexadecimal digits.
+               // i.e. 123456789 is represented by _val1 = 0x23456789 and _val2 = 0x1
+               private void InitDecHexDigits (uint value)
+               {
+                       if (value >= HundredMillion) {
+                               int div1 = (int)(value / HundredMillion);
+                               value -= HundredMillion * (uint)div1;
+                               _val2 = FastToDecHex (div1);
                        }
+                       _val1 = ToDecHex ((int)value);
+               }
 
-                       ns.AppendIntegerStringWithGroupSeparator (sb, nfi.CurrencyGroupSizes, nfi.CurrencyGroupSeparator);
-
-                       if (precision > 0)
-                       {
-                               sb.Append (nfi.CurrencyDecimalSeparator);
-                               ns.AppendDecimalString (precision, sb);
-                       }
+               // Translate an unsigned long to hexadecimal digits.
+               private void InitDecHexDigits (ulong value)
+               {
+                       if (value >= HundredMillion) {
+                               long div1 = (long)(value / HundredMillion);
+                               value -= HundredMillion * (ulong)div1;
+                               if (div1 >= HundredMillion) {
+                                       int div2 = (int)(div1 / HundredMillion);
+                                       div1 = div1 - div2 * (long)HundredMillion;
+                                       _val3 = ToDecHex (div2);
+                               }
+                               if (div1 != 0)
+                                       _val2 = ToDecHex ((int)(div1));
+                       }
+                       if (value != 0)
+                               _val1 = ToDecHex ((int)value);
+               }
 
-                       if (!needNegativeSign) {
-                               switch (nfi.CurrencyPositivePattern) {
-                               case 1:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 3:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               }
-                       } else {
-                               switch (nfi.CurrencyNegativePattern) {
-                               case 0:
-                                       sb.Append (')');
-                                       break;
-                               case 3:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 4:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (')');
-                                       break;
-                               case 5:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 6:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 7:
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 8:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 10:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 11:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 13:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (' ');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       break;
-                               case 14:
-                                       sb.Append (')');
-                                       break;
-                               case 15:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.CurrencySymbol);
-                                       sb.Append (')');
-                                       break;
-                               }
+               // Translate a decimal integer to hexadecimal digits.
+               // The decimal integer is 96 digits and its value is hi * 2^64 + lo.
+               // is the lower 64 bits.
+               private void InitDecHexDigits (uint hi, ulong lo)
+               {
+                       if (hi == 0) {
+                               InitDecHexDigits (lo); // Only the lower 64 bits matter.
+                               return;
                        }
 
-                       return sb.ToString ();
+                       // Compute (hi, lo) = (hi , lo) / HundredMillion.
+                       uint divhi = hi / HundredMillion;
+                       ulong remhi = hi - divhi * HundredMillion;
+                       ulong divlo = lo / HundredMillion;
+                       ulong remlo = lo - divlo * HundredMillion + remhi * ULongModHundredMillion;
+                       hi = divhi;
+                       lo = divlo + remhi * ULongDivHundredMillion;
+                       divlo = remlo / HundredMillion;
+                       remlo -= divlo * HundredMillion;
+                       lo += divlo;
+                       _val1 = ToDecHex ((int)remlo);
+
+                       // Divide hi * 2 ^ 64 + lo by HundredMillion using the fact that
+                       // hi < HundredMillion.
+                       divlo = lo / HundredMillion;
+                       remlo = lo - divlo * HundredMillion;
+                       lo = divlo;
+                       if (hi != 0) {
+                               lo += hi * ULongDivHundredMillion;
+                               remlo += hi * ULongModHundredMillion;
+                               divlo = remlo / HundredMillion;
+                               lo += divlo;
+                               remlo -= divlo * HundredMillion;
+                       }
+                       _val2 = ToDecHex ((int)remlo);
+
+                       // Now we are left with 64 bits store in lo.
+                       if (lo >= HundredMillion) {
+                               divlo = lo / HundredMillion;
+                               lo -= divlo * HundredMillion;
+                               _val4 = ToDecHex ((int)divlo);
+                       }
+                       _val3 = ToDecHex ((int)lo);
                }
-               internal static string FormatDecimal (NumberStore ns, int precision, NumberFormatInfo nfi)
-               {
-                       if (ns.IsFloatingSource || ns.IsDecimalSource)
-                               throw new FormatException ();
 
-                       precision = precision > 0 ? precision : 1;
-                       precision = ns.IntegerDigits > precision ? ns.IntegerDigits : precision;
+               // Helper to translate an int in the range 0 .. 9999 to its
+               // Hexadecimal digits representation.
+#if UNSAFE_TABLES
+               unsafe
+#endif
+               private static uint FastToDecHex (int val)
+               {
+                       if (val < 100)
+                               return (uint)DecHexDigits [val];
 
-                       StringBuilder sb = new StringBuilder (precision + nfi.NegativeSign.Length);
+                       // Uses 2^19 (524288) to compute val / 100 for val < 10000.
+                       int v = (val * 5243) >> 19;
+                       return (uint)((DecHexDigits [v] << 8) | DecHexDigits [val - v * 100]);
+               }
 
-                       if (!ns.Positive && !ns.CheckZeroOnlyInteger ()) {
-                               sb.Append (nfi.NegativeSign);
+               // Helper to translate an int in the range 0 .. 99999999 to its
+               // Hexadecimal digits representation.
+               private static uint ToDecHex (int val)
+               {
+                       uint res = 0;
+                       if (val >= 10000) {
+                               int v = val / 10000;
+                               val -= v * 10000;
+                               res = FastToDecHex (v) << 16;
                        }
-
-                       ns.AppendIntegerString (precision, sb);
-
-                       return sb.ToString ();
+                       return res | FastToDecHex (val);
                }
-               internal static string FormatFixedPoint (NumberStore ns, int precision, NumberFormatInfo nfi)
-               {
-                       precision = precision >= 0 ? precision : nfi.NumberDecimalDigits;
-                       ns.RoundDecimal (precision);
-
-                       StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + nfi.NumberDecimalSeparator.Length);
 
-                       if (!ns.Positive && !ns.ZeroOnly)
-                               cb.Append (nfi.NegativeSign);
+               // Helper to count number of hexadecimal digits in a number.
+               private static int FastDecHexLen (int val)
+               {
+                       if (val < 0x100)
+                               if (val < 0x10)
+                                       return 1;
+                               else
+                                       return 2;
+                       else if (val < 0x1000)
+                               return 3;
+                       else
+                               return 4;
+               }
 
-                       ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+               private static int DecHexLen (uint val)
+               {
+                       if (val < 0x10000)
+                               return FastDecHexLen ((int)val);
+                       return 4 + FastDecHexLen ((int)(val >> 16));
+               }
 
-                       if (precision > 0) {
-                               cb.Append (nfi.NumberDecimalSeparator);
-                               ns.AppendDecimalString (precision, cb);
-                       }
+               // Count number of hexadecimal digits stored in _val1 .. _val4.
+               private int DecHexLen ()
+               {
+                       if (_val4 != 0)
+                               return DecHexLen (_val4) + 24;
+                       else if (_val3 != 0)
+                               return DecHexLen (_val3) + 16;
+                       else if (_val2 != 0)
+                               return DecHexLen (_val2) + 8;
+                       else if (_val1 != 0)
+                               return DecHexLen (_val1);
+                       else
+                               return 0;
+               }
 
-                       return cb.ToString ();
+               // Helper to count the 10th scale (number of digits) in a number
+               private static int ScaleOrder (long hi)
+               {
+                       for (int i = TenPowersListLength - 1; i >= 0; i--)
+                               if (hi >= GetTenPowerOf (i))
+                                       return i + 1;
+                       return 1;
                }
 
-               internal static string FormatGeneral (NumberStore ns)
+               // Compute the initial precision for rounding a floating number
+               // according to the used format.
+               int InitialFloatingPrecision ()
                {
-                       return FormatGeneral (ns, -1, NumberFormatInfo.CurrentInfo, true, false);
+                       if (_specifier == 'R')
+                               return _defPrecision + 2;
+                       if (_precision < _defPrecision)
+                               return _defPrecision;
+                       if (_specifier == 'G')
+                               return Math.Min (_defPrecision + 2, _precision);
+                       if (_specifier == 'E')
+                               return Math.Min (_defPrecision + 2, _precision + 1);
+                       return _defPrecision;
                }
-               internal static string FormatGeneral (NumberStore ns, IFormatProvider provider)
+
+               // Parse the given format and extract the precision in it.
+               // Returns -1 for empty formats and -2 to indicate that the format
+               // is a custom format.
+               private static int ParsePrecision (string format)
                {
-                       return FormatGeneral (ns, -1, NumberFormatInfo.GetInstance (provider), true, false);
+                       int precision = 0;
+                       for (int i = 1; i < format.Length; i++) {
+                               int val = format [i] - '0';
+                               precision = precision * 10 + val;
+                               if (val < 0 || val > 9 || precision > 99)
+                                       return -2;
+                       }
+                       return precision;
                }
-               private static string FormatGeneral (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper, bool roundtrip)
+
+               #endregion Constructor Helpers
+
+               #region Constructors
+
+               // Parse the given format and initialize the following fields:
+               //   _isCustomFormat, _specifierIsUpper, _specifier & _precision.
+               public NumberFormatter (Thread current)
                {
-                       if (ns.ZeroOnly)
-                               return "0";
+                       _cbuf = EmptyArray<char>.Value;
+                       if (current == null)
+                               return;
+                       CurrentCulture = current.CurrentCulture;
+               }
 
-                       precision = precision > 0 ? precision : ns.DefaultPrecision;
-
-                       int exponent = 0;
-                       bool expMode = (ns.IsDecimalSource && precision == ns.DefaultPrecision ? false : (ns.IntegerDigits > precision || ns.DecimalPointPosition <= -4));
-                       if (expMode) {
-                               while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
-                                       if (ns.DecimalPointPosition > 1) {
-                                               ns.Divide10 (1);
-                                               exponent ++;
-                                       } else {
-                                               ns.Multiply10 (1);
-                                               exponent --;
-                                       }
-                               }
+               private void Init (string format)
+               {
+                       _val1 = _val2 = _val3 = _val4 = 0;
+                       _offset = 0;
+                       _NaN = _infinity = false;
+                       _isCustomFormat = false;
+                       _specifierIsUpper = true;
+                       _precision = -1;
+
+                       if (format == null || format.Length == 0) {
+                               _specifier = 'G';
+                               return;
                        }
 
-                       precision = precision < ns.DefaultPrecision + 2 ? (precision < ns.DefaultMaxPrecision ? precision : ns.DefaultMaxPrecision) : ns.DefaultPrecision + 2;
-                       StringBuilder cb = new StringBuilder (ns.IntegerDigits + precision + 16);
-                       if (expMode) {
-                               if (ns.RoundDecimal (precision - 1)) {
-                                       ns.Divide10 (1);
-                                       exponent ++;
+                       char specifier = format [0];
+                       if (specifier >= 'a' && specifier <= 'z') {
+                               specifier = (char)(specifier - 'a' + 'A');
+                               _specifierIsUpper = false;
+                       }
+                       else if (specifier < 'A' || specifier > 'Z') {
+                               _isCustomFormat = true;
+                               _specifier = '0';
+                               return;
+                       }
+                       _specifier = specifier;
+                       if (format.Length > 1) {
+                               _precision = ParsePrecision (format);
+                               if (_precision == -2) { // Is it a custom format?
+                                       _isCustomFormat = true;
+                                       _specifier = '0';
+                                       _precision = -1;
                                }
-                       } else if (!roundtrip) {
-                               if (ns.IsDecimalSource)
-                                       ns.RoundPos (precision);
-                               else
-                                       ns.RoundDecimal (precision, true, false);
                        }
+               }
 
-                       if (!ns.Positive) {
-                               cb.Append (nfi.NegativeSign);
-                       }
+               private void InitHex (ulong value)
+               {
+                       switch (_defPrecision) {
+                               case Int8DefPrecision:  value = (byte) value;    break;
+                               case Int16DefPrecision: value = (ushort) value;  break;
+                               case Int32DefPrecision: value = (uint) value;    break;
+                       }
+                       _val1 = (uint)value;
+                       _val2 = (uint)(value >> 32);
+                       _decPointPos = _digitsLen = DecHexLen ();
+                       if (value == 0)
+                               _decPointPos = 1;
+               }
 
-                       ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+               private void Init (string format, int value, int defPrecision)
+               {
+                       Init (format);
+                       _defPrecision = defPrecision;
+                       _positive = value >= 0;
 
-                       if (ns.DecimalDigits > 0) {
-                               cb.Append (nfi.NumberDecimalSeparator);
-                               ns.AppendDecimalString (ns.DecimalDigits, cb);
+                       if (value == 0 || _specifier == 'X') {
+                               InitHex ((ulong)value);
+                               return;
                        }
 
-                       if (expMode) {
-                               if (upper)
-                                       cb.Append ('E');
-                               else
-                                       cb.Append ('e');
+                       if (value < 0)
+                               value = -value;
+                       InitDecHexDigits ((uint)value);
+                       _decPointPos = _digitsLen = DecHexLen ();
+               }
 
-                               if (exponent >= 0)
-                                       cb.Append (nfi.PositiveSign);
-                               else {
-                                       cb.Append (nfi.NegativeSign);
-                                       exponent = -exponent;
-                               }
+               private void Init (string format, uint value, int defPrecision)
+               {
+                       Init (format);
+                       _defPrecision = defPrecision;
+                       _positive = true;
 
-                               if (exponent == 0) {
-                                       cb.Append ('0', 2);
-                               } else if (exponent < 10) {
-                                       cb.Append ('0');
-                                       cb.Append (digitLowerTable [exponent]);
-                               } else if (exponent < 100) {
-                                       cb.Append (digitLowerTable [exponent / 10 % 10]);
-                                       cb.Append (digitLowerTable [exponent % 10]);
-                               } else if (exponent < 1000) {
-                                       cb.Append (digitLowerTable [exponent / 100 % 10]);
-                                       cb.Append (digitLowerTable [exponent / 10 % 10]);
-                                       cb.Append (digitLowerTable [exponent % 10]);
-                               }
+                       if (value == 0 || _specifier == 'X') {
+                               InitHex (value);
+                               return;
                        }
 
-                       return cb.ToString ();
+                       InitDecHexDigits (value);
+                       _decPointPos = _digitsLen = DecHexLen ();
                }
-               internal static string FormatNumber (NumberStore ns, int precision, NumberFormatInfo nfi)
-               {
-                       precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
-                       StringBuilder sb = new StringBuilder(ns.IntegerDigits * 3 + precision);
 
-                       ns.RoundDecimal (precision);
-                       bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
+               private void Init (string format, long value)
+               {
+                       Init (format);
+                       _defPrecision = Int64DefPrecision;
+                       _positive = value >= 0;
 
-                       if (needNegativeSign) {
-                               switch (nfi.NumberNegativePattern) {
-                               case 0:
-                                       sb.Append ('(');
-                                       break;
-                               case 1:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 2:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (' ');
-                                       break;
-                               }
+                       if (value == 0 || _specifier == 'X') {
+                               InitHex ((ulong)value);
+                               return;
                        }
 
-                       ns.AppendIntegerStringWithGroupSeparator (sb, nfi.NumberGroupSizes, nfi.NumberGroupSeparator);
+                       if (value < 0)
+                               value = -value;
+                       InitDecHexDigits ((ulong)value);
+                       _decPointPos = _digitsLen = DecHexLen ();
+               }
 
-                       if (precision > 0) {
-                               sb.Append (nfi.NumberDecimalSeparator);
-                               ns.AppendDecimalString (precision, sb);
-                       }
+               private void Init (string format, ulong value)
+               {
+                       Init (format);
+                       _defPrecision = UInt64DefPrecision;
+                       _positive = true;
 
-                       if (needNegativeSign) {
-                               switch (nfi.NumberNegativePattern) {
-                               case 0:
-                                       sb.Append (')');
-                                       break;
-                               case 3:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 4:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               }
+                       if (value == 0 || _specifier == 'X') {
+                               InitHex ((ulong)value);
+                               return;
                        }
 
-                       return sb.ToString ();
+                       InitDecHexDigits (value);
+                       _decPointPos = _digitsLen = DecHexLen ();
                }
-               internal static string FormatPercent (NumberStore ns, int precision, NumberFormatInfo nfi)
-               {
-                       precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
-                       ns.Multiply10 (2);
-                       ns.RoundDecimal (precision);
-                       bool needNegativeSign = (!ns.Positive && !ns.ZeroOnly);
-
-                       StringBuilder sb = new StringBuilder(ns.IntegerDigits * 2 + precision + 16);
 
-                       if (!needNegativeSign) {
-                               if (nfi.PercentPositivePattern == 2) {
-                                       sb.Append (nfi.PercentSymbol);
-                               }
-                       } else {
-                               switch (nfi.PercentNegativePattern) {
-                               case 0:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 1:
-                                       sb.Append (nfi.NegativeSign);
-                                       break;
-                               case 2:
-                                       sb.Append (nfi.NegativeSign);
-                                       sb.Append (nfi.PercentSymbol);
-                                       break;
-                               }
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+               unsafe
+#endif
+               private void Init (string format, double value, int defPrecision)
+               {
+                       Init (format);
+
+                       _defPrecision = defPrecision;
+                       long bits = BitConverter.DoubleToInt64Bits (value);
+                       _positive = bits >= 0;
+                       bits &= Int64.MaxValue;
+                       if (bits == 0) {
+                               _decPointPos = 1;
+                               _digitsLen = 0;
+                               _positive = true;
+                               return;
                        }
 
-                       ns.AppendIntegerStringWithGroupSeparator (sb, nfi.PercentGroupSizes, nfi.PercentGroupSeparator);
-                       
-                       if (precision > 0) {
-                               sb.Append (nfi.PercentDecimalSeparator);
-                               ns.AppendDecimalString (precision, sb);
+                       int e = (int)(bits >> DoubleBitsExponentShift);
+                       long m = bits & DoubleBitsMantissaMask;
+                       if (e == DoubleBitsExponentMask) {
+                               _NaN = m != 0;
+                               _infinity = m == 0;
+                               return;
                        }
 
-                       if (!needNegativeSign) {
-                               switch (nfi.PercentPositivePattern) {
-                               case 0:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.PercentSymbol);
-                                       break;
-                               case 1:
-                                       sb.Append (nfi.PercentSymbol);
-                                       break;
-                               }
-                       } else {
-                               switch (nfi.PercentNegativePattern) {
-                               case 0:
-                                       sb.Append (' ');
-                                       sb.Append (nfi.PercentSymbol);
-                                       break;
-                               case 1:
-                                       sb.Append (nfi.PercentSymbol);
-                                       break;
+                       int expAdjust = 0;
+                       if (e == 0) {
+                               // We need 'm' to be large enough so we won't lose precision.
+                               e = 1;
+                               int scale = ScaleOrder (m);
+                               if (scale < DoubleDefPrecision) {
+                                       expAdjust = scale - DoubleDefPrecision;
+                                       m *= GetTenPowerOf (-expAdjust);
                                }
                        }
-
-                       return sb.ToString ();
+                       else {
+                               m = (m + DoubleBitsMantissaMask + 1) * 10;
+                               expAdjust = -1;
+                       }
+
+                       // multiply the mantissa by 10 ^ N
+                       ulong lo = (uint)m;
+                       ulong hi = (ulong)m >> 32;
+                       ulong lo2 = MantissaBitsTable [e];
+                       ulong hi2 = lo2 >> 32;
+                       lo2 = (uint)lo2;
+                       ulong mm = hi * lo2 + lo * hi2 + ((lo * lo2) >> 32);
+                       long res = (long)(hi * hi2 + (mm >> 32));
+                       while (res < SeventeenDigitsThreshold) {
+                               mm = (mm & UInt32.MaxValue) * 10;
+                               res = res * 10 + (long)(mm >> 32);
+                               expAdjust--;
+                       }
+                       if ((mm & 0x80000000) != 0)
+                               res++;
+
+                       int order = DoubleDefPrecision + 2;
+                       _decPointPos = TensExponentTable [e] + expAdjust + order;
+
+                       // Rescale 'res' to the initial precision (15-17 for doubles).
+                       int initialPrecision = InitialFloatingPrecision ();
+                       if (order > initialPrecision) {
+                               long val = GetTenPowerOf (order - initialPrecision);
+                               res = (res + (val >> 1)) / val;
+                               order = initialPrecision;
+                       }
+                       if (res >= GetTenPowerOf (order)) {
+                               order++;
+                               _decPointPos++;
+                       }
+
+                       InitDecHexDigits ((ulong)res);
+                       _offset = CountTrailingZeros ();
+                       _digitsLen = order - _offset;
                }
-               unsafe static string FormatHexadecimal (ulong value, bool positive, int byteSize, int precision, bool upper)
+
+               private void Init (string format, decimal value)
                {
-                       if (!positive) {
-                               /* for large values the cast to ulong is going to return 0 anyway (at least on x86, possibly a MS/Mono runtime bug) */
-#if FALSE
-                               if (byteSize < 8) {
-                                       value = (ulong)(Math.Pow (2, byteSize * 8)) - value;
-                               } else {
-                                       value = 0 - value;
-                               }
-#else
-                               switch (byteSize) {
-                               case 1:
-                                       value = (ulong)(256UL - value);
-                                       break;
-                               case 2:
-                                       value = (ulong)(65536UL - value);
-                                       break;
-                               case 4:
-                                       value = (ulong)(4294967296UL - value);
-                                       break;
-                               case 8:
-                                       value = 0 - value;
-                                       break;
-                               }
-#endif
+                       Init (format);
+                       _defPrecision = DecimalDefPrecision;
+
+                       int[] bits = decimal.GetBits (value);
+                       int scale = (bits [3] & DecimalBitsScaleMask) >> 16;
+                       _positive = bits [3] >= 0;
+                       if (bits [0] == 0 && bits [1] == 0 && bits [2] == 0) {
+                               _decPointPos = -scale;
+                               _positive = true;
+                               _digitsLen = 0;
+                               return;
                        }
 
-                       char[] digits = (upper ? digitUpperTable : digitLowerTable);
-                       int size = precision > 16 ? precision : 16;
-                       char* buffer = stackalloc char [size];
-                       char* last = buffer + size;
-                       char* ptr = last;
-                       
-                       while (value > 0) {
-                               *--ptr = digits[value & 0xF];
-                               value >>= 4;
+                       InitDecHexDigits ((uint)bits [2], ((ulong)bits [1] << 32) | (uint)bits [0]);
+                       _digitsLen = DecHexLen ();
+                       _decPointPos = _digitsLen - scale;
+                       if (_precision != -1 || _specifier != 'G') {
+                               _offset = CountTrailingZeros ();
+                               _digitsLen -= _offset;
                        }
+               }
 
-                       while (ptr == last || last - ptr < precision)
-                               *--ptr = '0';
+               #endregion Constructors
 
-                       return new string (ptr, 0, (int)(last - ptr));
+               #region Inner String Buffer
+
+               //_cbuf moved to before other fields to improve layout
+               private int _ind;
+
+               private void ResetCharBuf (int size)
+               {
+                       _ind = 0;
+                       if (_cbuf.Length < size)
+                               _cbuf = new char [size];
                }
-               internal static string FormatExponential (NumberStore ns, int precision, NumberFormatInfo nfi, bool upper)
+
+               private void Resize (int len)
                {
-                       if (precision < 0)
-                               precision = 6;
+                       Array.Resize (ref _cbuf, len);
+               }
 
-                       if (ns.ZeroOnly) {
-                               StringBuilder sb = new StringBuilder (precision + nfi.PositiveSign.Length + 6);
-                               sb.Append ('0');
-                               if (precision > 0) {
-                                       sb.Append ('.');
-                                       sb.Append ('0', precision);
-                               }
+               private void Append (char c)
+               {
+                       if (_ind == _cbuf.Length)
+                               Resize (_ind + 10);
+                       _cbuf [_ind++] = c;
+               }
 
-                               if (upper)
-                                       sb.Append ('E');
-                               else
-                                       sb.Append ('e');
+               private void Append (char c, int cnt)
+               {
+                       if (_ind + cnt > _cbuf.Length)
+                               Resize (_ind + cnt + 10);
+                       while (cnt-- > 0)
+                               _cbuf [_ind++] = c;
+               }
 
-                               sb.Append (nfi.PositiveSign);
-                               sb.Append ('0', 3);
-                               
-                               return sb.ToString ();
-                       }
+               private void Append (string s)
+               {
+                       int slen = s.Length;
+                       if (_ind + slen > _cbuf.Length)
+                               Resize (_ind + slen + 10);
+                       for (int i = 0; i < slen; i++)
+                               _cbuf [_ind++] = s [i];
+               }
 
-                       int exponent = 0;
-                       while (!(ns.DecimalPointPosition == 1 && ns.GetChar (0) != '0')) {
-                               if (ns.DecimalPointPosition > 1) {
-                                       ns.Divide10 (1);
-                                       exponent ++;
-                               } else {
-                                       ns.Multiply10 (1);
-                                       exponent --;
-                               }
-                       }
+               #endregion Inner String Buffer
 
-                       if (ns.RoundDecimal (precision)) {
-                               ns.Divide10 (1);
-                               exponent ++;
-                       }
+               #region Helper properties
 
-                       StringBuilder cb = new StringBuilder (ns.DecimalDigits + 1 + 8);
+               private NumberFormatInfo GetNumberFormatInstance (IFormatProvider fp)
+               {
+                       if (_nfi != null && fp == null)
+                               return _nfi;
+                       return NumberFormatInfo.GetInstance (fp);
+               }
 
-                       if (!ns.Positive) {
-                               cb.Append (nfi.NegativeSign);
+               public CultureInfo CurrentCulture {
+                       set {
+                               if (value != null && value.IsReadOnly)
+                                       _nfi = value.NumberFormat;
+                               else
+                                       _nfi = null;
                        }
+               }
 
-                       ns.AppendIntegerString (ns.IntegerDigits > 0 ? ns.IntegerDigits : 1, cb);
+               private int IntegerDigits {
+                       get { return _decPointPos > 0 ? _decPointPos : 1; }
+               }
 
-                       if (precision > 0) {
-                               cb.Append (nfi.NumberDecimalSeparator);
-                               ns.AppendDecimalString (precision, cb);
-                       }
+               private int DecimalDigits {
+                       get { return _digitsLen > _decPointPos ? _digitsLen - _decPointPos : 0; }
+               }
 
-                       if (upper)
-                               cb.Append ('E');
-                       else
-                               cb.Append ('e');
+               private bool IsFloatingSource {
+                       get { return _defPrecision == DoubleDefPrecision || _defPrecision == SingleDefPrecision; }
+               }
 
-                       if (exponent >= 0)
-                               cb.Append (nfi.PositiveSign);
-                       else {
-                               cb.Append (nfi.NegativeSign);
-                               exponent = -exponent;
-                       }
+               private bool IsZero {
+                       get { return _digitsLen == 0; }
+               }
 
-                       if (exponent == 0) {
-                               cb.Append ('0', 3);
-                       } else if (exponent < 10) {
-                               cb.Append ('0', 2);
-                               cb.Append (digitLowerTable [exponent]);
-                       } else if (exponent < 100) {
-                               cb.Append ('0', 1);
-                               cb.Append (digitLowerTable [exponent / 10 % 10]);
-                               cb.Append (digitLowerTable [exponent % 10]);
-                       } else if (exponent < 1000) {
-                               cb.Append (digitLowerTable [exponent / 100 % 10]);
-                               cb.Append (digitLowerTable [exponent / 10 % 10]);
-                               cb.Append (digitLowerTable [exponent % 10]);
-                       /*} else { // exponent range is 0...+-324
-                               int pos = cb.Length;
-                               int count = 3;
-                               while (exponent > 0 || --count > 0) {
-                                       cb.Insert (pos, digitLowerTable [exponent % 10]);
-                                       exponent /= 10;
-                               }*/
-                       }
-
-                       return cb.ToString ();
+               private bool IsZeroInteger {
+                       get { return _digitsLen == 0 || _decPointPos <= 0; }
                }
-               #endregion
 
-               #region Custom
-               internal static string FormatCustom (string format, NumberStore ns, NumberFormatInfo nfi)
+               #endregion Helper properties
+
+               #region Round
+
+               private void RoundPos (int pos)
                {
-                       bool p = ns.Positive;
-                       int offset = 0;
-                       int length = 0;
-                       CustomInfo.GetActiveSection (format,ref p, ns.ZeroOnly, ref offset, ref length);
-                       if (length == 0) {
-                               return ns.Positive ? String.Empty : nfi.NegativeSign;
-                       }
-                       ns.Positive = p;
+                       RoundBits (_digitsLen - pos);
+               }
 
-                       CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
-#if false
-                       Console.WriteLine("Format : {0}",format);
-                       Console.WriteLine("DecimalDigits : {0}",info.DecimalDigits);
-                       Console.WriteLine("DecimalPointPos : {0}",info.DecimalPointPos);
-                       Console.WriteLine("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
-                       Console.WriteLine("IntegerDigits : {0}",info.IntegerDigits);
-                       Console.WriteLine("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
-                       Console.WriteLine("IntegerHeadPos : {0}",info.IntegerHeadPos);
-                       Console.WriteLine("UseExponent : {0}",info.UseExponent);
-                       Console.WriteLine("ExponentDigits : {0}",info.ExponentDigits);
-                       Console.WriteLine("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
-                       Console.WriteLine("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
-                       Console.WriteLine("DividePlaces : {0}",info.DividePlaces);
-                       Console.WriteLine("Percents : {0}",info.Percents);
-                       Console.WriteLine("Permilles : {0}",info.Permilles);
-#endif
-                       StringBuilder sb_int = new StringBuilder(info.IntegerDigits * 2);
-                       StringBuilder sb_dec = new StringBuilder(info.DecimalDigits * 2);
-                       StringBuilder sb_exp = (info.UseExponent ? new StringBuilder(info.ExponentDigits * 2) : null);
+               private bool RoundDecimal (int decimals)
+               {
+                       return RoundBits (_digitsLen - _decPointPos - decimals);
+               }
 
-                       int diff = 0;
-                       if (info.Percents > 0) {
-                               ns.Multiply10 (2 * info.Percents);
-                       }
-                       if (info.Permilles > 0) {
-                               ns.Multiply10 (3 * info.Permilles);
-                       }
-                       if (info.DividePlaces > 0) {
-                               ns.Divide10 (info.DividePlaces);
+               private bool RoundBits (int shift)
+               {
+                       if (shift <= 0)
+                               return false;
+
+                       if (shift > _digitsLen) {
+                               _digitsLen = 0;
+                               _decPointPos = 1;
+                               _val1 = _val2 = _val3 = _val4 = 0;
+                               _positive = true;
+                               return false;
                        }
+                       shift += _offset;
+                       _digitsLen += _offset;
+                       while (shift > 8) {
+                               _val1 = _val2;
+                               _val2 = _val3;
+                               _val3 = _val4;
+                               _val4 = 0;
+                               _digitsLen -= 8;
+                               shift -= 8;
+                       }
+                       shift = (shift - 1) << 2;
+                       uint v = _val1 >> shift;
+                       uint rem16 = v & 0xf;
+                       _val1 = (v ^ rem16) << shift;
+                       bool res = false;
+                       if (rem16 >= 0x5) {
+                               _val1 |= 0x99999999 >> (28 - shift);
+                               AddOneToDecHex ();
+                               int newlen = DecHexLen ();
+                               res = newlen != _digitsLen;
+                               _decPointPos = _decPointPos + newlen - _digitsLen;
+                               _digitsLen = newlen;
+                       }
+                       RemoveTrailingZeros ();
+                       return res;
+               }
 
-                       bool expPositive = true;
-                       if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
-                               if (!ns.ZeroOnly) {
-                                       while (true) {
-                                               while (ns.IntegerDigits > info.IntegerDigits) {
-                                                       ns.Divide10 (1);
-                                                       diff--;
-                                                       if (ns.IntegerDigits == 1 && ns.GetChar (0) == '0')
-                                                               break;
-                                               }
-                                               while (ns.IntegerDigits < info.IntegerDigits || (ns.IntegerDigits == info.IntegerDigits && ns.GetChar (0) == '0')) {
-                                                       ns.Multiply10 (1);
-                                                       diff++;
-                                               }
+               private void RemoveTrailingZeros ()
+               {
+                       _offset = CountTrailingZeros ();
+                       _digitsLen -= _offset;
+                       if (_digitsLen == 0) {
+                               _offset = 0;
+                               _decPointPos = 1;
+                               _positive = true;
+                       }
+               }
 
-                                               if (!ns.RoundDecimal (info.DecimalDigits))
-                                                       break;
+               private void AddOneToDecHex ()
+               {
+                       if (_val1 == 0x99999999) {
+                               _val1 = 0;
+                               if (_val2 == 0x99999999) {
+                                       _val2 = 0;
+                                       if (_val3 == 0x99999999) {
+                                               _val3 = 0;
+                                               _val4 = AddOneToDecHex (_val4);
                                        }
+                                       else
+                                               _val3 = AddOneToDecHex (_val3);
                                }
-
-                               expPositive = diff <= 0;
-                               NumberStore.AppendIntegerStringFromUInt32 (sb_exp, (uint)(diff >= 0 ? diff : -diff));
-                       } else {
-                               ns.RoundDecimal (info.DecimalDigits);
-                               if (ns.ZeroOnly)
-                                       ns.Positive = true;
+                               else
+                                       _val2 = AddOneToDecHex (_val2);
                        }
+                       else
+                               _val1 = AddOneToDecHex (_val1);
+               }
 
-                       if (info.IntegerDigits != 0 || !ns.CheckZeroOnlyInteger ()) {
-                               ns.AppendIntegerString (ns.IntegerDigits, sb_int);
-                       }
-                       /* if (sb_int.Length > info.IntegerDigits) {
-                               int len = 0;
-                               while (sb_int.Length > info.IntegerDigits && len < sb_int.Length) {
-                                       if (sb_int [len] == '0')
-                                               len ++;
+               // Assume val != 0x99999999
+               private static uint AddOneToDecHex (uint val)
+               {
+                       if ((val & 0xffff) == 0x9999)
+                               if ((val & 0xffffff) == 0x999999)
+                                       if ((val & 0xfffffff) == 0x9999999)
+                                               return val + 0x06666667;
                                        else
-                                               break;
-                               }
-                               sb_int.Remove (0, len);
-                       } */
+                                               return val + 0x00666667;
+                               else if ((val & 0xfffff) == 0x99999)
+                                       return val + 0x00066667;
+                               else
+                                       return val + 0x00006667;
+                       else if ((val & 0xff) == 0x99)
+                               if ((val & 0xfff) == 0x999)
+                                       return val + 0x00000667;
+                               else
+                                       return val + 0x00000067;
+                       else if ((val & 0xf) == 0x9)
+                               return val + 0x00000007;
+                       else
+                               return val + 1;
+               }
 
-                       ns.AppendDecimalString (ns.DecimalDigits, sb_dec);
+               private int CountTrailingZeros ()
+               {
+                       if (_val1 != 0)
+                               return CountTrailingZeros (_val1);
+                       if (_val2 != 0)
+                               return CountTrailingZeros (_val2) + 8;
+                       if (_val3 != 0)
+                               return CountTrailingZeros (_val3) + 16;
+                       if (_val4 != 0)
+                               return CountTrailingZeros (_val4) + 24;
+                       return _digitsLen;
+               }
 
-                       if (info.UseExponent) {
-                               if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
-                                       ns.Positive = true;
+               private static int CountTrailingZeros (uint val)
+               {
+                       if ((val & 0xffff) == 0)
+                               if ((val & 0xffffff) == 0)
+                                       if ((val & 0xfffffff) == 0)
+                                               return 7;
+                                       else
+                                               return 6;
+                               else if ((val & 0xfffff) == 0)
+                                       return 5;
+                               else
+                                       return 4;
+                       else if ((val & 0xff) == 0)
+                               if ((val & 0xfff) == 0)
+                                       return 3;
+                               else
+                                       return 2;
+                       else if ((val & 0xf) == 0)
+                               return 1;
+                       else
+                               return 0;
+               }
 
-                               if (sb_int.Length < info.IntegerDigits)
-                                       sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
+               #endregion Round
 
-                               while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
-                                       sb_exp.Insert (0, '0');
+               #region public number formatting methods
 
-                               if (expPositive && !info.ExponentNegativeSignOnly)
-                                       sb_exp.Insert (0, nfi.PositiveSign);
-                               else if(!expPositive)
-                                       sb_exp.Insert (0, nfi.NegativeSign);
-                       } else {
-                               if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
-                                       sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
-                               if (info.IntegerDigits == info.IntegerHeadSharpDigits && NumberStore.IsZeroOnly (sb_int))
-                                       sb_int.Remove (0, sb_int.Length);
-                       }
+               [ThreadStatic]
+               static NumberFormatter threadNumberFormatter;
 
-                       ZeroTrimEnd (sb_dec, true);
-                       while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
-                               sb_dec.Append ('0');
-                       if (sb_dec.Length > info.DecimalDigits)
-                               sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
+               private static NumberFormatter GetInstance()
+               {
+                       NumberFormatter res = threadNumberFormatter;
+                       threadNumberFormatter = null;
+                       if (res == null)
+                               return new NumberFormatter (Thread.CurrentThread);
+                       res.CurrentCulture = Thread.CurrentThread.CurrentCulture;
+                       return res;
+               }
 
-                       return info.Format (format, offset, length, nfi, ns.Positive, sb_int, sb_dec, sb_exp);
+               private void Release()
+               {
+                       threadNumberFormatter = this;
                }
 
-               private class CustomInfo
+               public static string NumberToString (string format, sbyte value, IFormatProvider fp)
                {
-                       public bool UseGroup = false;
-                       public int DecimalDigits = 0;
-                       public int DecimalPointPos = -1;
-                       public int DecimalTailSharpDigits = 0;
-                       public int IntegerDigits = 0;
-                       public int IntegerHeadSharpDigits = 0;
-                       public int IntegerHeadPos = 0;
-                       public bool UseExponent = false;
-                       public int ExponentDigits = 0;
-                       public int ExponentTailSharpDigits = 0;
-                       public bool ExponentNegativeSignOnly = true;
-                       public int DividePlaces = 0;
-                       public int Percents = 0;
-                       public int Permilles = 0;
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, Int8DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                       public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
-                       {
-                               int[] lens = new int [3];
-                               int index = 0;
-                               int lastPos = 0;
-                               char literal = '\0';
-                               for (int i = 0; i < format.Length; i++) {
-                                       char c = format [i];
+               public static string NumberToString (string format, byte value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, UInt8DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                                       if (c == literal || (literal == '\0' && (c == '\"' || c == '\''))) {
-                                               if (literal == '\0')
-                                                       literal = c;
-                                               else
-                                                       literal = '\0';
-                                               continue;
-                                       }
-                                       
-                                       if (literal == '\0' && format [i] == ';' && (i == 0 || format [i - 1] != '\\')) {
-                                               lens [index ++] = i - lastPos;
-                                               lastPos = i + 1;
-                                               if (index == 3)
-                                                       break;
-                                       }
-                               }
+               public static string NumberToString (string format, ushort value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, Int16DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                               if (index == 0) {
-                                       offset = 0;
-                                       length = format.Length;
-                                       return;
-                               }
-                               if (index == 1) {
-                                       if (positive || zero) {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                                       if (lens [0] + 1 < format.Length) {
-                                               positive = true;
-                                               offset = lens [0] + 1;
-                                               length = format.Length - offset;
-                                               return;
-                                       } else {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                               }
-                               if (index == 2) {
-                                       if (zero) {
-                                               offset = lens [0] + lens [1] + 2;
-                                               length = format.Length - offset;
-                                               return;
-                                       }
-                                       if (positive) {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                                       if (lens [1] > 0) {
-                                               positive = true;
-                                               offset = lens [0] + 1;
-                                               length = lens [1];
-                                               return;
-                                       } else {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                               }
-                               if (index == 3) {
-                                       if (zero) {
-                                               offset = lens [0] + lens [1] + 2;
-                                               length = lens [2];
-                                               return;
-                                       }
-                                       if (positive) {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                                       if (lens [1] > 0) {
-                                               positive = true;
-                                               offset = lens [0] + 1;
-                                               length = lens [1];
-                                               return;
-                                       } else {
-                                               offset = 0;
-                                               length = lens [0];
-                                               return;
-                                       }
-                               }
+               public static string NumberToString (string format, short value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, UInt16DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                               throw new ArgumentException ();
-                       }
+               public static string NumberToString (string format, uint value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, Int32DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                       public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
-                       {
-                               char literal = '\0';
-                               bool integerArea = true;
-                               bool decimalArea = false;
-                               bool exponentArea = false;
-                               bool sharpContinues = true;
+               public static string NumberToString (string format, int value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, UInt32DefPrecision);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                               CustomInfo info = new CustomInfo ();
-                               int groupSeparatorCounter = 0;
+               public static string NumberToString (string format, ulong value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                               for (int i = offset; i - offset < length; i++) {
-                                       char c = format [i];
+               public static string NumberToString (string format, long value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value);
+                       string res = inst.IntegerToString (format, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                                       if (c == literal && c != '\0') {
-                                               literal = '\0';
-                                               continue;
-                                       }
-                                       if (literal != '\0')
-                                               continue;
+               public static string NumberToString (string format, float value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, SingleDefPrecision);
+                       NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+                       string res;
+                       if (inst._NaN)
+                               res = nfi.NaNSymbol;
+                       else if (inst._infinity)
+                               if (inst._positive)
+                                       res = nfi.PositiveInfinitySymbol;
+                               else
+                                       res = nfi.NegativeInfinitySymbol;
+                       else if (inst._specifier == 'R')
+                               res = inst.FormatRoundtrip (value, nfi);
+                       else
+                               res = inst.NumberToString (format, nfi);
+                       inst.Release();
+                       return res;
+               }
 
-                                       if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
-                                               exponentArea = false;
-                                               integerArea = (info.DecimalPointPos < 0);
-                                               decimalArea = !integerArea;
-                                               i--;
-                                               continue;
-                                       }
+               public static string NumberToString (string format, double value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value, DoubleDefPrecision);
+                       NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+                       string res;
+                       if (inst._NaN)
+                               res = nfi.NaNSymbol;
+                       else if (inst._infinity)
+                               if (inst._positive)
+                                       res = nfi.PositiveInfinitySymbol;
+                               else
+                                       res = nfi.NegativeInfinitySymbol;
+                       else if (inst._specifier == 'R')
+                               res = inst.FormatRoundtrip (value, nfi);
+                       else
+                               res = inst.NumberToString (format, nfi);
+                       inst.Release();
+                       return res;
+               }
 
-                                       switch (c) {
-                                       case '\\':
-                                               i ++;
-                                               continue;
-                                       case '\'':
-                                       case '\"':
-                                               if (c == '\"' || c == '\'') {
-                                                       literal = c;
-                                               }
-                                               continue;
-                                       case '#':
-                                               if (sharpContinues && integerArea)
-                                                       info.IntegerHeadSharpDigits ++;
-                                               else if (decimalArea)
-                                                       info.DecimalTailSharpDigits ++;
-                                               else if (exponentArea)
-                                                       info.ExponentTailSharpDigits ++;
+               public static string NumberToString (string format, decimal value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (format, value);
+                       string res = inst.NumberToString (format, inst.GetNumberFormatInstance (fp));
+                       inst.Release();
+                       return res;
+               }
 
-                                               goto case '0';
-                                       case '0':
-                                               if (c != '#') {
-                                                       sharpContinues = false;
-                                                       if (decimalArea)
-                                                               info.DecimalTailSharpDigits = 0;
-                                                       else if (exponentArea)
-                                                               info.ExponentTailSharpDigits = 0;
-                                               }
-                                               if (info.IntegerHeadPos == -1)
-                                                       info.IntegerHeadPos = i;
+               public static string NumberToString (uint value, IFormatProvider fp)
+               {
+                       if (value >= HundredMillion)
+                               return NumberToString (null, value, fp);
 
-                                               if (integerArea) {
-                                                       info.IntegerDigits ++;
-                                                       if (groupSeparatorCounter > 0)
-                                                               info.UseGroup = true;
-                                                       groupSeparatorCounter = 0;
-                                               } else if (decimalArea) {
-                                                       info.DecimalDigits ++;
-                                               } else if (exponentArea) {
-                                                       info.ExponentDigits ++;
-                                               }
-                                               break;
-                                       case 'e':
-                                       case 'E':
-                                               if (info.UseExponent)
-                                                       break;
+                       NumberFormatter inst = GetInstance();
+                       string res = inst.FastIntegerToString ((int)value, fp);
+                       inst.Release();
+                       return res;
+               }
 
-                                               info.UseExponent = true;
-                                               integerArea = false;
-                                               decimalArea = false;
-                                               exponentArea = true;
-                                               if (i + 1 - offset < length) {
-                                                       char nc = format [i + 1];
-                                                       if (nc == '+')
-                                                               info.ExponentNegativeSignOnly = false;
-                                                       if (nc == '+' || nc == '-') {
-                                                               i ++;
-                                                       } else if (nc != '0' && nc != '#') {
-                                                               info.UseExponent = false;
-                                                               if (info.DecimalPointPos < 0)
-                                                                       integerArea = true;
-                                                       }
-                                                       c = '\0';
-                                               }
-                                               
-                                               break;
-                                       case '.':
-                                               integerArea = false;
-                                               decimalArea = true;
-                                               exponentArea = false;
-                                               if (info.DecimalPointPos == -1)
-                                                       info.DecimalPointPos = i;
-                                               break;
-                                       case '%':
-                                               info.Percents++;
-                                               break;
-                                       case '\u2030':
-                                               info.Permilles++;
-                                               break;
-                                       case ',':
-                                               if (integerArea && info.IntegerDigits > 0)
-                                                       groupSeparatorCounter ++;
-                                               break;
-                                       default:
-                                               break;
-                                       }
-                               }
+               public static string NumberToString (int value, IFormatProvider fp)
+               {
+                       if (value >= HundredMillion || value <= -HundredMillion)
+                               return NumberToString (null, value, fp);
 
-                               if (info.ExponentDigits == 0)
-                                       info.UseExponent = false;
+                       NumberFormatter inst = GetInstance();
+                       string res = inst.FastIntegerToString (value, fp);
+                       inst.Release();
+                       return res;
+               }
+
+               public static string NumberToString (ulong value, IFormatProvider fp)
+               {
+                       if (value >= HundredMillion)
+                               return NumberToString (null, value, fp);
+
+                       NumberFormatter inst = GetInstance();
+                       string res = inst.FastIntegerToString ((int)value, fp);
+                       inst.Release();
+                       return res;
+               }
+
+               public static string NumberToString (long value, IFormatProvider fp)
+               {
+                       if (value >= HundredMillion || value <= -HundredMillion)
+                               return NumberToString (null, value, fp);
+
+                       NumberFormatter inst = GetInstance();
+                       string res = inst.FastIntegerToString ((int)value, fp);
+                       inst.Release();
+                       return res;
+               }
+
+               public static string NumberToString (float value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       inst.Init (null, value, SingleDefPrecision);
+                       NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+                       string res;
+                       if (inst._NaN)
+                               res = nfi.NaNSymbol;
+                       else if (inst._infinity)
+                               if (inst._positive)
+                                       res = nfi.PositiveInfinitySymbol;
                                else
-                                       info.IntegerHeadSharpDigits = 0;
+                                       res = nfi.NegativeInfinitySymbol;
+                       else
+                               res = inst.FormatGeneral (-1, nfi);
+                       inst.Release();
+                       return res;
+               }
 
-                               if (info.DecimalDigits == 0)
-                                       info.DecimalPointPos = -1;
+               public static string NumberToString (double value, IFormatProvider fp)
+               {
+                       NumberFormatter inst = GetInstance();
+                       NumberFormatInfo nfi = inst.GetNumberFormatInstance (fp);
+                       inst.Init (null, value, DoubleDefPrecision);
+                       string res;
+                       if (inst._NaN)
+                               res = nfi.NaNSymbol;
+                       else if (inst._infinity)
+                               if (inst._positive)
+                                       res = nfi.PositiveInfinitySymbol;
+                               else
+                                       res = nfi.NegativeInfinitySymbol;
+                       else
+                               res = inst.FormatGeneral (-1, nfi);
+                       inst.Release();
+                       return res;
+               }
 
-                               info.DividePlaces += groupSeparatorCounter * 3;
+               private string FastIntegerToString (int value, IFormatProvider fp)
+               {
+                       if (value < 0) {
+                               string sign = GetNumberFormatInstance(fp).NegativeSign;
+                               ResetCharBuf (8 + sign.Length);
+                               value = -value;
+                               Append (sign);
+                       }
+                       else
+                               ResetCharBuf (8);
 
-                               return info;
+                       if (value >= 10000) {
+                               int v = value / 10000;
+                               FastAppendDigits (v, false);
+                               FastAppendDigits (value - v * 10000, true);
                        }
+                       else
+                               FastAppendDigits (value, false);
 
-                       public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
-                       {
-                               StringBuilder sb = new StringBuilder ();
-                               char literal = '\0';
-                               bool integerArea = true;
-                               bool decimalArea = false;
-                               int  intSharpCounter = 0;
-                               int sb_int_index = 0;
-                               int sb_dec_index = 0;
+                       return new string (_cbuf, 0, _ind);
+               }
 
-                               int[] groups = nfi.NumberGroupSizes;
-                               string groupSeparator = nfi.NumberGroupSeparator;
-                               int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0, fraction = 0;
-                               if (UseGroup && groups.Length > 0) {
-                                       intLen = sb_int.Length;
-                                       for (int i = 0; i < groups.Length; i++) {
-                                               total += groups [i];
-                                               if (total <= intLen)
-                                                       groupIndex = i;
-                                       }
-                                       groupSize = groups [groupIndex];
-                                       fraction = intLen > total ? intLen - total : 0;
-                                       if (groupSize == 0) {
-                                               while (groupIndex >= 0 && groups [groupIndex] == 0)
-                                                       groupIndex --;
-                                               
-                                               groupSize = fraction > 0 ? fraction : groups [groupIndex];
-                                       }
-                                       if (fraction == 0) {
-                                               counter = groupSize;
-                                       } else {
-                                               groupIndex += fraction / groupSize;
-                                               counter = fraction % groupSize;
-                                               if (counter == 0)
-                                                       counter = groupSize;
-                                               else
-                                                       groupIndex ++;
-                                       }
-                               } else {
-                                       UseGroup = false;
+               private string IntegerToString (string format, IFormatProvider fp)
+               {
+                       NumberFormatInfo nfi = GetNumberFormatInstance (fp);
+                       switch (_specifier) {
+                       case 'C':
+                               return FormatCurrency (_precision, nfi);
+                       case 'D':
+                               return FormatDecimal (_precision, nfi);
+                       case 'E':
+                               return FormatExponential (_precision, nfi);
+                       case 'F':
+                               return FormatFixedPoint (_precision, nfi);
+                       case 'G':
+                               if (_precision <= 0)
+                                       return FormatDecimal (-1, nfi);
+                               return FormatGeneral (_precision, nfi);
+                       case 'N':
+                               return FormatNumber (_precision, nfi);
+                       case 'P':
+                               return FormatPercent (_precision, nfi);
+                       case 'X':
+                               return FormatHexadecimal (_precision);
+                       default:
+                               if (_isCustomFormat)
+                                       return FormatCustom (format, nfi);
+                               throw new FormatException ("The specified format '" + format + "' is invalid");
+                       }
+               }
+
+               private string NumberToString (string format, NumberFormatInfo nfi)
+               {
+                       switch (_specifier) {
+                       case 'C':
+                               return FormatCurrency (_precision, nfi);
+                       case 'E':
+                               return FormatExponential (_precision, nfi);
+                       case 'F':
+                               return FormatFixedPoint (_precision, nfi);
+                       case 'G':
+                               return FormatGeneral (_precision, nfi);
+                       case 'N':
+                               return FormatNumber (_precision, nfi);
+                       case 'P':
+                               return FormatPercent (_precision, nfi);
+                       case 'X':
+                       default:
+                               if (_isCustomFormat)
+                                       return FormatCustom (format, nfi);
+                               throw new FormatException ("The specified format '" + format + "' is invalid");
+                       }
+               }
+
+               public string FormatCurrency (int precision, NumberFormatInfo nfi)
+               {
+                       precision = (precision >= 0 ? precision : nfi.CurrencyDecimalDigits);
+                       RoundDecimal (precision);
+                       ResetCharBuf (IntegerDigits * 2 + precision * 2 + 16);
+
+                       if (_positive) {
+                               switch (nfi.CurrencyPositivePattern) {
+                               case 0:
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 2:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (' ');
+                                       break;
                                }
+                       }
+                       else {
+                               switch (nfi.CurrencyNegativePattern) {
+                               case 0:
+                                       Append ('(');
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 1:
+                                       Append (nfi.NegativeSign);
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 2:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 3:
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 4:
+                                       Append ('(');
+                                       break;
+                               case 5:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 8:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 9:
+                                       Append (nfi.NegativeSign);
+                                       Append (nfi.CurrencySymbol);
+                                       Append (' ');
+                                       break;
+                               case 11:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (' ');
+                                       break;
+                               case 12:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (' ');
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 14:
+                                       Append ('(');
+                                       Append (nfi.CurrencySymbol);
+                                       Append (' ');
+                                       break;
+                               case 15:
+                                       Append ('(');
+                                       break;
+                               }
+                       }
 
-                               for (int i = offset; i - offset < length; i++) {
-                                       char c = format [i];
+                       AppendIntegerStringWithGroupSeparator (nfi.RawCurrencyGroupSizes, nfi.CurrencyGroupSeparator);
 
-                                       if (c == literal && c != '\0') {
-                                               literal = '\0';
-                                               continue;
-                                       }
-                                       if (literal != '\0') {
-                                               sb.Append (c);
-                                               continue;
-                                       }
+                       if (precision > 0) {
+                               Append (nfi.CurrencyDecimalSeparator);
+                               AppendDecimalString (precision);
+                       }
 
-                                       switch (c) {
-                                       case '\\':
-                                               i ++;
-                                               if (i - offset < length)
-                                                       sb.Append (format [i]);
-                                               continue;
-                                       case '\'':
-                                       case '\"':
-                                               if (c == '\"' || c == '\'') {
-                                                       literal = c;
-                                               }
-                                               continue;
-                                       case '#':
-                                               goto case '0';
-                                       case '0':
-                                               if (integerArea) {
-                                                       intSharpCounter++;
-                                                       if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
-                                                               while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
-                                                                       sb.Append (sb_int[ sb_int_index++]);
-                                                                       if (UseGroup && --intLen > 0 && --counter == 0) {
-                                                                               sb.Append (groupSeparator);
-                                                                               if (--groupIndex < groups.Length && groupIndex >= 0)
-                                                                                       groupSize = groups [groupIndex];
-                                                                               counter = groupSize;
-                                                                       }
-                                                               }
-                                                       break;
-                                               } else if (decimalArea) {
-                                                       if (sb_dec_index < sb_dec.Length)
-                                                               sb.Append (sb_dec [sb_dec_index++]);
-                                                       break;
-                                               }
+                       if (_positive) {
+                               switch (nfi.CurrencyPositivePattern) {
+                               case 1:
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 3:
+                                       Append (' ');
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               }
+                       }
+                       else {
+                               switch (nfi.CurrencyNegativePattern) {
+                               case 0:
+                                       Append (')');
+                                       break;
+                               case 3:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 4:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (')');
+                                       break;
+                               case 5:
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 6:
+                                       Append (nfi.NegativeSign);
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 7:
+                                       Append (nfi.CurrencySymbol);
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 8:
+                                       Append (' ');
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 10:
+                                       Append (' ');
+                                       Append (nfi.CurrencySymbol);
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 11:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 13:
+                                       Append (nfi.NegativeSign);
+                                       Append (' ');
+                                       Append (nfi.CurrencySymbol);
+                                       break;
+                               case 14:
+                                       Append (')');
+                                       break;
+                               case 15:
+                                       Append (' ');
+                                       Append (nfi.CurrencySymbol);
+                                       Append (')');
+                                       break;
+                               }
+                       }
 
-                                               sb.Append (c);
-                                               break;
-                                       case 'e':
-                                       case 'E':
-                                               if (sb_exp == null || !UseExponent) {
-                                                       sb.Append (c);
-                                                       break;
-                                               }
+                       return new string (_cbuf, 0, _ind);
+               }
+
+               private string FormatDecimal (int precision, NumberFormatInfo nfi)
+               {
+                       if (precision < _digitsLen)
+                               precision = _digitsLen;
+                       if (precision == 0)
+                               return "0";
+
+                       ResetCharBuf (precision + 1);
+                       if (!_positive)
+                               Append (nfi.NegativeSign);
+                       AppendDigits (0, precision);
+
+                       return new string (_cbuf, 0, _ind);
+               }
+
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+               unsafe
+#endif
+               private string FormatHexadecimal (int precision)
+               {
+                       int size = Math.Max (precision, _decPointPos);
+#if UNSAFE_TABLES
+                       char* digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
+#else
+                       char[] digits = _specifierIsUpper ? DigitUpperTable : DigitLowerTable;
+#endif
+                       ResetCharBuf (size);
+                       _ind = size;
+                       ulong val = _val1 | ((ulong)_val2 << 32);
+                       while (size > 0) {
+                               _cbuf [--size] = digits [val & 0xf];
+                               val >>= 4;
+                       }
+                       return new string (_cbuf, 0, _ind);
+               }
+
+               public string FormatFixedPoint (int precision, NumberFormatInfo nfi)
+               {
+                       if (precision == -1)
+                               precision = nfi.NumberDecimalDigits;
+
+                       RoundDecimal (precision);
+
+                       ResetCharBuf (IntegerDigits + precision + 2);
+
+                       if (!_positive)
+                               Append (nfi.NegativeSign);
+
+                       AppendIntegerString (IntegerDigits);
+
+                       if (precision > 0) {
+                               Append (nfi.NumberDecimalSeparator);
+                               AppendDecimalString (precision);
+                       }
+
+                       return new string (_cbuf, 0, _ind);
+               }
+
+               private string FormatRoundtrip (double origval, NumberFormatInfo nfi)
+               {
+                       NumberFormatter nfc = GetClone ();
+                       if (origval >= MinRoundtripVal && origval <= MaxRoundtripVal) {
+                               string shortRep = FormatGeneral (_defPrecision, nfi);
+                               if (origval == Double.Parse (shortRep, nfi))
+                                       return shortRep;
+                       }
+                       return nfc.FormatGeneral (_defPrecision + 2, nfi);
+               }
+
+               private string FormatRoundtrip (float origval, NumberFormatInfo nfi)
+               {
+                       NumberFormatter nfc = GetClone ();
+                       string shortRep = FormatGeneral (_defPrecision, nfi);
+                       // Check roundtrip only for "normal" double values.
+                       if (origval == Single.Parse (shortRep, nfi))
+                               return shortRep;
+                       return nfc.FormatGeneral (_defPrecision + 2, nfi);
+               }
 
-                                               bool flag1 = true;
-                                               bool flag2 = false;
-                                               
-                                               int q;
-                                               for (q = i + 1; q - offset < length; q++) {
-                                                       if (format [q] == '0') {
-                                                               flag2 = true;
-                                                               continue;
-                                                       }
-                                                       if (q == i + 1 && (format [q] == '+' || format [q] == '-')) {
-                                                               continue;
-                                                       }
-                                                       if (!flag2)
-                                                               flag1 = false;
-                                                       break;
-                                               }
+               private string FormatGeneral (int precision, NumberFormatInfo nfi)
+               {
+                       bool enableExp;
+                       if (precision == -1) {
+                               enableExp = IsFloatingSource;
+                               precision = _defPrecision;
+                       }
+                       else {
+                               enableExp = true;
+                               if (precision == 0)
+                                       precision = _defPrecision;
+                               RoundPos (precision);
+                       }
 
-                                               if (flag1) {
-                                                       i = q - 1;
-                                                       integerArea = (DecimalPointPos < 0);
-                                                       decimalArea = !integerArea;
+                       int intDigits = _decPointPos;
+                       int digits = _digitsLen;
+                       int decDigits = digits - intDigits;
 
-                                                       sb.Append (c);
-                                                       sb.Append (sb_exp);
-                                                       sb_exp = null;
-                                               } else
-                                                       sb.Append (c);
+                       if ((intDigits > precision || intDigits <= -4) && enableExp)
+                               return FormatExponential (digits - 1, nfi, 2);
 
-                                               break;
-                                       case '.':
-                                               if (DecimalPointPos == i) {
-                                                       if (DecimalDigits > 0) {
-                                                               while (sb_int_index < sb_int.Length)
-                                                                       sb.Append (sb_int [sb_int_index++]);
-                                                       }
-                                                       if (sb_dec.Length > 0)
-                                                               sb.Append (nfi.NumberDecimalSeparator);
-                                               }
-                                               integerArea = false;
-                                               decimalArea = true;
-                                               break;
-                                       case ',':
-                                               break;
-                                       case '%':
-                                               sb.Append (nfi.PercentSymbol);
-                                               break;
-                                       case '\u2030':
-                                               sb.Append (nfi.PerMilleSymbol);
-                                               break;
-                                       default:
-                                               sb.Append (c);
-                                               break;
-                                       }
-                               }
+                       if (decDigits < 0)
+                               decDigits = 0;
+                       if (intDigits < 0)
+                               intDigits = 0;
+                       ResetCharBuf (decDigits + intDigits + 3);
 
-                               if (!positive)
-                                       sb.Insert (0, nfi.NegativeSign);
+                       if (!_positive)
+                               Append (nfi.NegativeSign);
 
-                               return sb.ToString ();
+                       if (intDigits == 0)
+                               Append ('0');
+                       else
+                               AppendDigits (digits - intDigits, digits);
+
+                       if (decDigits > 0) {
+                               Append (nfi.NumberDecimalSeparator);
+                               AppendDigits (0, decDigits);
                        }
+
+                       return new string (_cbuf, 0, _ind);
                }
 
-               #endregion
+               public string FormatNumber (int precision, NumberFormatInfo nfi)
+               {
+                       precision = (precision >= 0 ? precision : nfi.NumberDecimalDigits);
+                       ResetCharBuf (IntegerDigits * 3 + precision);
+                       RoundDecimal (precision);
 
-               #region Internal structures
-               internal struct NumberStore
-               {
-                       bool _NaN;
-                       bool _infinity;
-                       bool _positive;
-                       int  _decPointPos;
-                       int  _defPrecision;
-                       int  _defMaxPrecision;
-                       int  _defByteSize;
-
-                       byte[] _digits;
-
-                       static uint [] IntList = new uint [] {
-                               1,
-                               10,
-                               100,
-                               1000,
-                               10000,
-                               100000,
-                               1000000,
-                               10000000,
-                               100000000,
-                               1000000000,
-                       };
-
-                       static ulong [] ULongList = new ulong [] {
-                               1,
-                               10,
-                               100,
-                               1000,
-                               10000,
-                               100000,
-                               1000000,
-                               10000000,
-                               100000000,
-                               1000000000,
-                               10000000000,
-                               100000000000,
-                               1000000000000,
-                               10000000000000,
-                               100000000000000,
-                               1000000000000000,
-                               10000000000000000,
-                               100000000000000000,
-                               1000000000000000000,
-                               10000000000000000000,
-                       };
-
-                       #region Constructors
-                       public NumberStore (long value)
-                       {
-                               _infinity = _NaN = false;
-                               _defByteSize = 8;
-                               _defMaxPrecision = _defPrecision = 19;
-                               _positive = value >= 0;
-
-                               if (value == 0) {
-                                       _digits = new byte []{0};
-                                       _decPointPos = 1;
-                                       return;
+                       if (!_positive) {
+                               switch (nfi.NumberNegativePattern) {
+                               case 0:
+                                       Append ('(');
+                                       break;
+                               case 1:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 2:
+                                       Append (nfi.NegativeSign);
+                                       Append (' ');
+                                       break;
                                }
-                               
-                               ulong v = (ulong)(_positive ? value : -value);
-
-                               int i = 18, j = 0;
-
-                               if (v < 10)
-                                       i = 0;
-                               else if (v < 100)
-                                       i = 1;
-                               else if (v < 1000)
-                                       i = 2;
-                               else if (v < 10000)
-                                       i = 3;
-                               else if (v < 100000)
-                                       i = 4;
-                               else if (v < 1000000)
-                                       i = 5;
-                               else if (v < 10000000)
-                                       i = 6;
-                               else if (v < 100000000)
-                                       i = 7;
-                               else if (v < 1000000000)
-                                       i = 8;
-                               else if (v < 10000000000)
-                                       i = 9;
-                               else if (v < 100000000000)
-                                       i = 10;
-                               else if (v < 1000000000000)
-                                       i = 11;
-                               else if (v < 10000000000000)
-                                       i = 12;
-                               else if (v < 100000000000000)
-                                       i = 13;
-                               else if (v < 1000000000000000)
-                                       i = 14;
-                               else if (v < 10000000000000000)
-                                       i = 15;
-                               else if (v < 100000000000000000)
-                                       i = 16;
-                               else if (v < 1000000000000000000)
-                                       i = 17;
-                               else
-                                       i = 18;
+                       }
 
-                               _digits = new byte [i + 1];
-                               do {
-                                       ulong n = v / ULongList [i];
-                                       _digits [j++] = (byte)n;
-                                       v -= ULongList [i--] * n;
-                               } while (i >= 0);
+                       AppendIntegerStringWithGroupSeparator (nfi.RawNumberGroupSizes, nfi.NumberGroupSeparator);
 
-                               _decPointPos = _digits.Length;
+                       if (precision > 0) {
+                               Append (nfi.NumberDecimalSeparator);
+                               AppendDecimalString (precision);
                        }
-                       public NumberStore (int value)
-                       {
-                               _infinity = _NaN = false;
-                               _defByteSize = 4;
-                               _defMaxPrecision = _defPrecision = 10;
-                               _positive = value >= 0;
-
-                               if (value == 0) {
-                                       _digits = new byte []{0};
-                                       _decPointPos = 1;
-                                       return;
+
+                       if (!_positive) {
+                               switch (nfi.NumberNegativePattern) {
+                               case 0:
+                                       Append (')');
+                                       break;
+                               case 3:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 4:
+                                       Append (' ');
+                                       Append (nfi.NegativeSign);
+                                       break;
                                }
-                               
-                               uint v = (uint)(_positive ? value : -value);
-
-                               int i = 9, j = 0;
-
-                               if (v < 10)
-                                       i = 0;
-                               else if (v < 100)
-                                       i = 1;
-                               else if (v < 1000)
-                                       i = 2;
-                               else if (v < 10000)
-                                       i = 3;
-                               else if (v < 100000)
-                                       i = 4;
-                               else if (v < 1000000)
-                                       i = 5;
-                               else if (v < 10000000)
-                                       i = 6;
-                               else if (v < 100000000)
-                                       i = 7;
-                               else if (v < 1000000000)
-                                       i = 8;
-                               else
-                                       i = 9;
+                       }
 
-                               _digits = new byte [i + 1];
-                               do {
-                                       uint n = v / IntList [i];
-                                       _digits [j++] = (byte)n;
-                                       v -= IntList [i--] * n;
-                               } while (i >= 0);
+                       return new string (_cbuf, 0, _ind);
+               }
 
-                               _decPointPos = _digits.Length;
-                       }
-                       public NumberStore (short value) : this ((int)value)
-                       {
-                               _defByteSize = 2;
-                               _defMaxPrecision = _defPrecision = 5;
+               public string FormatPercent (int precision, NumberFormatInfo nfi)
+               {
+                       precision = (precision >= 0 ? precision : nfi.PercentDecimalDigits);
+                       Multiply10(2);
+                       RoundDecimal (precision);
+                       ResetCharBuf (IntegerDigits * 2 + precision + 16);
+
+                       if (_positive) {
+                               if (nfi.PercentPositivePattern == 2)
+                                       Append (nfi.PercentSymbol);
                        }
-                       public NumberStore (sbyte value) : this ((int)value)
-                       {
-                               _defByteSize = 1;
-                               _defMaxPrecision = _defPrecision = 3;
+                       else {
+                               switch (nfi.PercentNegativePattern) {
+                               case 0:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 1:
+                                       Append (nfi.NegativeSign);
+                                       break;
+                               case 2:
+                                       Append (nfi.NegativeSign);
+                                       Append (nfi.PercentSymbol);
+                                       break;
+                               }
                        }
 
-                       public NumberStore (ulong value)
-                       {
-                               _infinity = _NaN = false;
-                               _defByteSize = 8;
-                               _defMaxPrecision = _defPrecision = 20;
-                               _positive = true;
+                       AppendIntegerStringWithGroupSeparator (nfi.RawPercentGroupSizes, nfi.PercentGroupSeparator);
 
-                               if (value == 0) {
-                                       _digits = new byte []{0};
-                                       _decPointPos = 1;
-                                       return;
+                       if (precision > 0) {
+                               Append (nfi.PercentDecimalSeparator);
+                               AppendDecimalString (precision);
+                       }
+
+                       if (_positive) {
+                               switch (nfi.PercentPositivePattern) {
+                               case 0:
+                                       Append (' ');
+                                       Append (nfi.PercentSymbol);
+                                       break;
+                               case 1:
+                                       Append (nfi.PercentSymbol);
+                                       break;
+                               }
+                       }
+                       else {
+                               switch (nfi.PercentNegativePattern) {
+                               case 0:
+                                       Append (' ');
+                                       Append (nfi.PercentSymbol);
+                                       break;
+                               case 1:
+                                       Append (nfi.PercentSymbol);
+                                       break;
                                }
+                       }
 
-                               int i = 19, j = 0;
-
-                               if (value < 10)
-                                       i = 0;
-                               else if (value < 100)
-                                       i = 1;
-                               else if (value < 1000)
-                                       i = 2;
-                               else if (value < 10000)
-                                       i = 3;
-                               else if (value < 100000)
-                                       i = 4;
-                               else if (value < 1000000)
-                                       i = 5;
-                               else if (value < 10000000)
-                                       i = 6;
-                               else if (value < 100000000)
-                                       i = 7;
-                               else if (value < 1000000000)
-                                       i = 8;
-                               else if (value < 10000000000)
-                                       i = 9;
-                               else if (value < 100000000000)
-                                       i = 10;
-                               else if (value < 1000000000000)
-                                       i = 11;
-                               else if (value < 10000000000000)
-                                       i = 12;
-                               else if (value < 100000000000000)
-                                       i = 13;
-                               else if (value < 1000000000000000)
-                                       i = 14;
-                               else if (value < 10000000000000000)
-                                       i = 15;
-                               else if (value < 100000000000000000)
-                                       i = 16;
-                               else if (value < 1000000000000000000)
-                                       i = 17;
-                               else if (value < 10000000000000000000)
-                                       i = 18;
-                               else
-                                       i = 19;
+                       return new string (_cbuf, 0, _ind);
+               }
+
+               public string FormatExponential (int precision, NumberFormatInfo nfi)
+               {
+                       if (precision == -1)
+                               precision = DefaultExpPrecision;
 
-                               _digits = new byte [i + 1];
-                               do {
-                                       ulong n = value / ULongList [i];
-                                       _digits [j++] = (byte)n;
-                                       value -= ULongList [i--] * n;
-                               } while (i >= 0);
+                       RoundPos (precision + 1);
+                       return FormatExponential (precision, nfi, 3);
+               }
 
-                               _decPointPos = _digits.Length;
-                       }
-                       public NumberStore (uint value)
-                       {
-                               _infinity = _NaN = false;
-                               _positive = true;
-                               _defByteSize = 4;
-                               _defMaxPrecision = _defPrecision = 10;
+               private string FormatExponential (int precision, NumberFormatInfo nfi, int expDigits)
+               {
+                       int decDigits = _decPointPos;
+                       int digits = _digitsLen;
+                       int exponent = decDigits - 1;
+                       decDigits = _decPointPos = 1;
 
-                               if (value == 0) {
-                                       _digits = new byte []{0};
-                                       _decPointPos = 1;
-                                       return;
-                               }
-                               
-                               int i = 9, j = 0;
-
-                               if (value < 10)
-                                       i = 0;
-                               else if (value < 100)
-                                       i = 1;
-                               else if (value < 1000)
-                                       i = 2;
-                               else if (value < 10000)
-                                       i = 3;
-                               else if (value < 100000)
-                                       i = 4;
-                               else if (value < 1000000)
-                                       i = 5;
-                               else if (value < 10000000)
-                                       i = 6;
-                               else if (value < 100000000)
-                                       i = 7;
-                               else if (value < 1000000000)
-                                       i = 8;
-                               else
-                                       i = 9;
+                       ResetCharBuf (precision + 8);
 
-                               _digits = new byte [i + 1];
-                               do {
-                                       uint n = value / IntList [i];
-                                       _digits [j++] = (byte)n;
-                                       value -= IntList [i--] * n;
-                               } while (i >= 0);
+                       if (!_positive)
+                               Append (nfi.NegativeSign);
 
-                               _decPointPos = _digits.Length;
-                       }
-                       public NumberStore (ushort value) : this ((uint)value)
-                       {
-                               _defByteSize = 2;
-                               _defMaxPrecision = _defPrecision = 5;
-                       }
-                       public NumberStore (byte value) : this ((uint)value)
-                       {
-                               _defByteSize = 1;
-                               _defMaxPrecision = _defPrecision = 3;
+                       AppendOneDigit (digits - 1);
+
+                       if (precision > 0) {
+                               Append (nfi.NumberDecimalSeparator);
+                               AppendDigits (digits - precision - 1, digits - _decPointPos);
                        }
 
-                       public NumberStore(double value)
-                       {
-                               _digits = null;
-                               _defByteSize = 64;
-                               _defPrecision = 15;
-                               _defMaxPrecision = _defPrecision + 2;
-
-                               if (double.IsNaN (value) || double.IsInfinity (value)) {
-                                       _NaN = double.IsNaN (value);
-                                       _infinity = double.IsInfinity (value);
-                                       _positive = value > 0;
-                                       _decPointPos = 0;
-                                       return;
-                               } else {
-                                       _NaN = _infinity = false;
-                               }
+                       AppendExponent (nfi, exponent, expDigits);
 
-                               long bits = BitConverter.DoubleToInt64Bits (value);
-                               _positive = (bits >= 0);
-                               int e = (int) ((bits >> 52) & 0x7ffL);
-                               long m = bits & 0xfffffffffffffL;
+                       return new string (_cbuf, 0, _ind);
+               }
 
-                               if (e == 0 && m == 0) {
-                                       _decPointPos = 1;
-                                       _digits = new byte []{0};
-                                       _positive = true;
-                                       return;
-                               }
+               public string FormatCustom (string format, NumberFormatInfo nfi)
+               {
+                       bool p = _positive;
+                       int offset = 0;
+                       int length = 0;
+                       CustomInfo.GetActiveSection (format, ref p, IsZero, ref offset, ref length);
+                       if (length == 0)
+                               return _positive ? string.Empty : nfi.NegativeSign;
+                       _positive = p;
 
-                               if (e == 0) {
-                                       e ++;
-                               } else if (e != 0) {
-                                       m |= (1L << 52);
-                               }
+                       CustomInfo info = CustomInfo.Parse (format, offset, length, nfi);
+#if false
+                       Console.WriteLine ("Format : {0}",format);
+                       Console.WriteLine ("DecimalDigits : {0}",info.DecimalDigits);
+                       Console.WriteLine ("DecimalPointPos : {0}",info.DecimalPointPos);
+                       Console.WriteLine ("DecimalTailSharpDigits : {0}",info.DecimalTailSharpDigits);
+                       Console.WriteLine ("IntegerDigits : {0}",info.IntegerDigits);
+                       Console.WriteLine ("IntegerHeadSharpDigits : {0}",info.IntegerHeadSharpDigits);
+                       Console.WriteLine ("IntegerHeadPos : {0}",info.IntegerHeadPos);
+                       Console.WriteLine ("UseExponent : {0}",info.UseExponent);
+                       Console.WriteLine ("ExponentDigits : {0}",info.ExponentDigits);
+                       Console.WriteLine ("ExponentTailSharpDigits : {0}",info.ExponentTailSharpDigits);
+                       Console.WriteLine ("ExponentNegativeSignOnly : {0}",info.ExponentNegativeSignOnly);
+                       Console.WriteLine ("DividePlaces : {0}",info.DividePlaces);
+                       Console.WriteLine ("Percents : {0}",info.Percents);
+                       Console.WriteLine ("Permilles : {0}",info.Permilles);
+#endif
+                       StringBuilder sb_int = new StringBuilder (info.IntegerDigits * 2);
+                       StringBuilder sb_dec = new StringBuilder (info.DecimalDigits * 2);
+                       StringBuilder sb_exp = (info.UseExponent ? new StringBuilder (info.ExponentDigits * 2) : null);
 
-                               e -= 1075;
+                       int diff = 0;
+                       if (info.Percents > 0)
+                               Multiply10(2 * info.Percents);
+                       if (info.Permilles > 0)
+                               Multiply10(3 * info.Permilles);
+                       if (info.DividePlaces > 0)
+                               Divide10(info.DividePlaces);
 
-                               int nsize = 0;
-                               while ((m & 1) == 0) {
-                                       m >>= 1;
-                                       e ++;
-                                       nsize ++;
+                       bool expPositive = true;
+                       if (info.UseExponent && (info.DecimalDigits > 0 || info.IntegerDigits > 0)) {
+                               if (!IsZero) {
+                                       RoundPos (info.DecimalDigits + info.IntegerDigits);
+                                       diff -= _decPointPos - info.IntegerDigits;
+                                       _decPointPos = info.IntegerDigits;
                                }
 
-                               long mt = m;
-                               int length = 1;
-                               byte[] temp = new byte [56];
-                               for (int i = temp.Length - 1; i >= 0; i--, length++) {
-                                       temp [i] = (byte)(mt % 10);
-                                       mt /= 10;
-                                       if (mt == 0)
-                                               break;
-                               }
+                               expPositive = diff <= 0;
+                               AppendNonNegativeNumber (sb_exp, diff < 0 ? -diff : diff);
+                       }
+                       else
+                               RoundDecimal (info.DecimalDigits);
 
-                               _decPointPos = temp.Length - 1;
+                       if (info.IntegerDigits != 0 || !IsZeroInteger)
+                               AppendIntegerString (IntegerDigits, sb_int);
 
-                               if (e >= 0) {
-                                       for (int i = 0; i < e; i++) {
-                                               if (MultiplyBy (ref temp, ref length, 2)) {
-                                                       _decPointPos ++;
-                                               }
-                                       }
-                               } else {
-                                       for (int i = 0; i < -e; i++) {
-                                               if (MultiplyBy (ref temp, ref length, 5)) {
-                                                       _decPointPos ++;
-                                               }
-                                       }
-                                       _decPointPos += e;
-                               }
+                       AppendDecimalString (DecimalDigits, sb_dec);
 
-                               int ulvc = 1;
-                               ulong ulv = 0;
-                               for (int i = 0; i < temp.Length; i++)
-                                       if (temp [i] != 0) {
-                                               _decPointPos -= i - 1;
-                                               _digits = new byte [temp.Length - i];
-                                               for (int q = i; q < temp.Length; q++) {
-                                                       _digits [q - i] = temp [q];
-                                                       if (ulvc < 20) {
-                                                               ulv = ulv * 10 + temp [q];
-                                                               ulvc ++;
-                                                       }
-                                               }
-                                               break;
-                                       }
+                       if (info.UseExponent) {
+                               if (info.DecimalDigits <= 0 && info.IntegerDigits <= 0)
+                                       _positive = true;
+
+                               if (sb_int.Length < info.IntegerDigits)
+                                       sb_int.Insert (0, "0", info.IntegerDigits - sb_int.Length);
+
+                               while (sb_exp.Length < info.ExponentDigits - info.ExponentTailSharpDigits)
+                                       sb_exp.Insert (0, '0');
 
-                               RoundEffectiveDigits (17, true, true);
+                               if (expPositive && !info.ExponentNegativeSignOnly)
+                                       sb_exp.Insert (0, nfi.PositiveSign);
+                               else if (!expPositive)
+                                       sb_exp.Insert (0, nfi.NegativeSign);
+                       }
+                       else {
+                               if (sb_int.Length < info.IntegerDigits - info.IntegerHeadSharpDigits)
+                                       sb_int.Insert (0, "0", info.IntegerDigits - info.IntegerHeadSharpDigits - sb_int.Length);
+                               if (info.IntegerDigits == info.IntegerHeadSharpDigits && IsZeroOnly (sb_int))
+                                       sb_int.Remove (0, sb_int.Length);
                        }
-                       public NumberStore(float value)
-                       {
-                               _digits = null;
-                               _defByteSize = 32;
-                               _defPrecision = 7;
-                               _defMaxPrecision = _defPrecision + 2;
-
-                               if (float.IsNaN (value) || float.IsInfinity (value)) {
-                                       _NaN = float.IsNaN (value);
-                                       _infinity = float.IsInfinity (value);
-                                       _positive = value > 0;
-                                       _decPointPos = 0;
-                                       return;
-                               } else
-                                       _infinity = _NaN = false;
 
-                               long bits = BitConverter.DoubleToInt64Bits (value);
-                               _positive = (bits >= 0);
-                               int e = (int) ((bits >> 52) & 0x7ffL);
-                               long m = bits & 0xfffffffffffffL;
+                       ZeroTrimEnd (sb_dec, true);
+                       while (sb_dec.Length < info.DecimalDigits - info.DecimalTailSharpDigits)
+                               sb_dec.Append ('0');
+                       if (sb_dec.Length > info.DecimalDigits)
+                               sb_dec.Remove (info.DecimalDigits, sb_dec.Length - info.DecimalDigits);
 
-                               if (e == 0 && m == 0) {
-                                       _decPointPos = 1;
-                                       _digits = new byte []{0};
-                                       _positive = true;
-                                       return;
-                               }
+                       return info.Format (format, offset, length, nfi, _positive, sb_int, sb_dec, sb_exp);
+               }
+               #endregion public number formatting methods
 
-                               if (e == 0) {
-                                       e ++;
-                               } else if (e != 0) {
-                                       m |= (1L << 52);
-                               }
+               #region StringBuilder formatting helpers
 
-                               e -= 1075;
+               private static void ZeroTrimEnd (StringBuilder sb, bool canEmpty)
+               {
+                       int len = 0;
+                       for (int i = sb.Length - 1; (canEmpty ? i >= 0 : i > 0); i--) {
+                               if (sb [i] != '0')
+                                       break;
+                               len++;
+                       }
 
-                               int nsize = 0;
-                               while ((m & 1) == 0) {
-                                       m >>= 1;
-                                       e ++;
-                                       nsize ++;
-                               }
+                       if (len > 0)
+                               sb.Remove (sb.Length - len, len);
+               }
 
-                               long mt = m;
-                               int length = 1;
-                               byte[] temp = new byte [26];
-                               for (int i = temp.Length - 1; i >= 0; i--, length++) {
-                                       temp [i] = (byte)(mt % 10);
-                                       mt /= 10;
-                                       if (mt == 0)
-                                               break;
-                               }
+               private static bool IsZeroOnly (StringBuilder sb)
+               {
+                       for (int i = 0; i < sb.Length; i++)
+                               if (char.IsDigit (sb [i]) && sb [i] != '0')
+                                       return false;
+                       return true;
+               }
 
-                               _decPointPos = temp.Length - 1;
+               private static void AppendNonNegativeNumber (StringBuilder sb, int v)
+               {
+                       if (v < 0)
+                               throw new ArgumentException ();
 
-                               if (e >= 0) {
-                                       for (int i = 0; i < e; i++) {
-                                               if (MultiplyBy (ref temp, ref length, 2)) {
-                                                       _decPointPos ++;
-                                               }
-                                       }
-                               } else {
-                                       for (int i = 0; i < -e; i++) {
-                                               if (MultiplyBy (ref temp, ref length, 5)) {
-                                                       _decPointPos ++;
-                                               }
-                                       }
-                                       _decPointPos += e;
-                               }
+                       int i = ScaleOrder (v) - 1;
+                       do {
+                               int n = v / (int)GetTenPowerOf (i);
+                               sb.Append ((char)('0' | n));
+                               v -= (int)GetTenPowerOf (i--) * n;
+                       } while (i >= 0);
+               }
 
-                               int ulvc = 1;
-                               ulong ulv = 0;
-                               for (int i = 0; i < temp.Length; i++)
-                                       if (temp [i] != 0) {
-                                               _decPointPos -= i - 1;
-                                               _digits = new byte [temp.Length - i];
-                                               for (int q = i; q < temp.Length; q++) {
-                                                       _digits [q - i] = temp [q];
-                                                       if (ulvc < 20) {
-                                                               ulv = ulv * 10 + temp [q];
-                                                               ulvc ++;
-                                                       }
-                                               }
-                                               break;
-                                       }
+               #endregion StringBuilder formatting helpers
+
+               #region Append helpers
 
-                               RoundEffectiveDigits (9, true, true);
+               private void AppendIntegerString (int minLength, StringBuilder sb)
+               {
+                       if (_decPointPos <= 0) {
+                               sb.Append ('0', minLength);
+                               return;
                        }
 
-                       internal bool MultiplyBy (ref byte[] buffer,ref int length, int amount)
-                       {
-                               int mod = 0;
-                               int ret;
-                               int start = buffer.Length - length - 1;
-                               if (start < 0) start = 0;
-
-                               for (int i = buffer.Length - 1; i > start; i--) {
-                                       ret = buffer [i] * amount + mod;
-                                       mod = ret / 10;
-                                       buffer [i] = (byte)(ret % 10);
-                               }
+                       if (_decPointPos < minLength)
+                               sb.Append ('0', minLength - _decPointPos);
 
-                               if (mod != 0) {
-                                       length = buffer.Length - start;
+                       AppendDigits (_digitsLen - _decPointPos, _digitsLen, sb);
+               }
 
-                                       if (start == 0) {
-                                               buffer [0] = (byte)mod;
-                                               Array.Copy (buffer, 0, buffer, 1, buffer.Length - 1);
-                                               buffer [0] = 0;
-                                               return true;
-                                       }
-                                       else {
-                                               buffer [start] = (byte)mod;
-                                       }
-                               }
+               private void AppendIntegerString (int minLength)
+               {
+                       if (_decPointPos <= 0) {
+                               Append ('0', minLength);
+                               return;
+                       }
+
+                       if (_decPointPos < minLength)
+                               Append ('0', minLength - _decPointPos);
+
+                       AppendDigits (_digitsLen - _decPointPos, _digitsLen);
+               }
+
+               private void AppendDecimalString (int precision, StringBuilder sb)
+               {
+                       AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos, sb);
+               }
+
+               private void AppendDecimalString (int precision)
+               {
+                       AppendDigits (_digitsLen - precision - _decPointPos, _digitsLen - _decPointPos);
+               }
+
+               private void AppendIntegerStringWithGroupSeparator (int[] groups, string groupSeparator)
+               {
+                       if (IsZeroInteger) {
+                               Append ('0');
+                               return;
+                       }
 
-                               return false;
+                       int total = 0;
+                       int groupIndex = 0;
+                       for (int i = 0; i < groups.Length; i++) {
+                               total += groups [i];
+                               if (total <= _decPointPos)
+                                       groupIndex = i;
+                               else
+                                       break;
                        }
 
+                       if (groups.Length > 0 && total > 0) {
+                               int counter;
+                               int groupSize = groups [groupIndex];
+                               int fraction = _decPointPos > total ? _decPointPos - total : 0;
+                               if (groupSize == 0) {
+                                       while (groupIndex >= 0 && groups [groupIndex] == 0)
+                                               groupIndex--;
 
-                       public NumberStore (decimal value)
-                       {
-                               int[] bits = decimal.GetBits (value);
-                               _positive = (bits [3] & 0x80000000) == 0;
-                               bits[3] = bits [3] & 0x7FFFFFFF;
-                               int ss = (bits [3] & 0x1F0000) >> 16;
-                               ulong lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
-                               ulong hi = (uint)bits [2];
-                               uint rest = 0;
-
-                               int digits = 0;
-                               while (hi > 0 || lo > 0) {
-                                       digits ++;
-                                       DivideDecimal (ref lo, ref hi, 10, ref rest);
+                                       groupSize = fraction > 0 ? fraction : groups [groupIndex];
+                               }
+                               if (fraction == 0)
+                                       counter = groupSize;
+                               else {
+                                       groupIndex += fraction / groupSize;
+                                       counter = fraction % groupSize;
+                                       if (counter == 0)
+                                               counter = groupSize;
+                                       else
+                                               groupIndex++;
                                }
 
-                               lo = (ulong)((((ulong)bits[1]) << 32) | (uint)bits [0]);
-                               hi = (uint)bits [2];
+                               if (total >= _decPointPos) {
+                                       int lastGroupSize = groups [0];
+                                       if (total > lastGroupSize) {
+                                               int lastGroupDiff = -(lastGroupSize - _decPointPos);
+                                               int lastGroupMod;
 
-                               _digits = new byte [digits];
-                               int i = digits;
-                               while (hi > 0 || lo > 0) {
-                                       DivideDecimal (ref lo, ref hi, 10, ref rest);
-                                       _digits [--i] = (byte)rest;
+                                               if (lastGroupDiff < lastGroupSize)
+                                                       counter = lastGroupDiff;
+                                               else if (lastGroupSize > 0 && (lastGroupMod = _decPointPos % lastGroupSize) > 0)
+                                                       counter = lastGroupMod;
+                                       }
+                               }
+                               
+                               for (int i = 0; ;) {
+                                       if ((_decPointPos - i) <= counter || counter == 0) {
+                                               AppendDigits (_digitsLen - _decPointPos, _digitsLen - i);
+                                               break;
+                                       }
+                                       AppendDigits (_digitsLen - i - counter, _digitsLen - i);
+                                       i += counter;
+                                       Append (groupSeparator);
+                                       if (--groupIndex < groups.Length && groupIndex >= 0)
+                                               groupSize = groups [groupIndex];
+                                       counter = groupSize;
                                }
-
-                               _infinity = _NaN = false;
-                               _decPointPos = _digits.Length - ss;
-                               _defPrecision = _defMaxPrecision = 100;
-                               _defByteSize = 16;
-                       }
-                       static int DivideDecimal (ref ulong lo, ref ulong hi, uint factor, ref uint rest)
-                       {
-                               ulong a, b, c, h;
-
-                               h = hi;
-                               a = (uint)(h >> 32);
-                               b = a / factor;
-                               a -= b * factor;
-                               a <<= 32;
-                               a |= (uint) h;
-                               c = a / factor;
-                               a -= c * factor;
-                               a <<= 32;
-                               hi = b << 32 | (uint)c;
-
-                               h = lo;
-                               a |= (uint)(h >> 32);
-                               b = a / factor;
-                               a -= b * factor;
-                               a <<= 32;
-                               a |= (uint) h;
-                               c = a / factor;
-                               a -= c * factor;
-                               lo = b << 32 | (uint)c;
-
-                               rest = (uint)a;
-
-                               a <<= 1;
-                               return (a >= factor || (a == factor && (c & 1) == 1)) ? 1 : 0;
-                       }
-                       #endregion
-
-                       #region Public Property
-                       public bool IsNaN 
-                       {
-                               get { return _NaN; }
-                       }
-                       public bool IsInfinity {
-                               get { return _infinity; }
-                       }
-                       public int DecimalPointPosition {
-                               get { return _decPointPos; }
-                       }
-                       public bool Positive {
-                               get { return _positive; }
-                               set { _positive = value;}
-                       }
-                       public int DefaultPrecision {
-                               get { return _defPrecision; }
-                       }
-                       public int DefaultMaxPrecision {
-                               get { return _defMaxPrecision; }
-                       }
-                       public int DefaultByteSize {
-                               get { return _defByteSize; }
                        }
-                       public bool HasDecimal {
-                               get { return _digits.Length > _decPointPos; }
+                       else {
+                               AppendDigits (_digitsLen - _decPointPos, _digitsLen);
                        }
-                       public int IntegerDigits {
-                               get { return _decPointPos > 0 ? _decPointPos : 1; }
+               }
+
+               // minDigits is in the range 1..3
+               private void AppendExponent (NumberFormatInfo nfi, int exponent, int minDigits)
+               {
+                       if (_specifierIsUpper || _specifier == 'R')
+                               Append ('E');
+                       else
+                               Append ('e');
+
+                       if (exponent >= 0)
+                               Append (nfi.PositiveSign);
+                       else {
+                               Append (nfi.NegativeSign);
+                               exponent = -exponent;
                        }
-                       public int DecimalDigits {
-                               get { return HasDecimal ? _digits.Length - _decPointPos : 0; }
+
+                       if (exponent == 0)
+                               Append ('0', minDigits);
+                       else if (exponent < 10) {
+                               Append ('0', minDigits - 1);
+                               Append ((char)('0' | exponent));
                        }
-                       public bool IsFloatingSource {
-                               get { return _defPrecision == 15 || _defPrecision == 7; }
+                       else {
+                               uint hexDigit = FastToDecHex (exponent);
+                               if (exponent >= 100 || minDigits == 3)
+                                       Append ((char)('0' | (hexDigit >> 8)));
+                               Append ((char)('0' | ((hexDigit >> 4) & 0xf)));
+                               Append ((char)('0' | (hexDigit & 0xf)));
                        }
-                       public bool IsDecimalSource {
-                               get { return _defPrecision > 30; }
+               }
+
+               private void AppendOneDigit (int start)
+               {
+                       if (_ind == _cbuf.Length)
+                               Resize (_ind + 10);
+
+                       start += _offset;
+                       uint v;
+                       if (start < 0)
+                               v = 0;
+                       else if (start < 8)
+                               v = _val1;
+                       else if (start < 16)
+                               v = _val2;
+                       else if (start < 24)
+                               v = _val3;
+                       else if (start < 32)
+                               v = _val4;
+                       else
+                               v = 0;
+                       v >>= (start & 0x7) << 2;
+                       _cbuf [_ind++] = (char)('0' | v & 0xf);
+               }
+
+#if UNSAFE_TABLES // No unsafe code under TARGET_JVM
+               unsafe
+#endif
+               private void FastAppendDigits (int val, bool force)
+               {
+                       int i = _ind;
+                       int digits;
+                       if (force || val >= 100) {
+                               int v = (val * 5243) >> 19;
+                               digits = DecHexDigits [v];
+                               if (force || val >= 1000)
+                                       _cbuf [i++] = (char)('0' | digits >> 4);
+                               _cbuf [i++] = (char)('0' | (digits & 0xf));
+                               digits = DecHexDigits [val - v * 100];
                        }
-                       public bool IsBankerApplicable {
-                               get {
-                                       if ((_digits == null) || (_digits.Length < 2))
-                                               return false;
-                                       return ((_digits [_digits.Length - 2] & 1) == 1);
+                       else
+                               digits = DecHexDigits [val];
+
+                       if (force || val >= 10)
+                               _cbuf [i++] = (char)('0' | digits >> 4);
+                       _cbuf [i++] = (char)('0' | (digits & 0xf));
+                       _ind = i;
+               }
+
+               private void AppendDigits (int start, int end)
+               {
+                       if (start >= end)
+                               return;
+
+                       int i = _ind + (end - start);
+                       if (i > _cbuf.Length)
+                               Resize (i + 10);
+                       _ind = i;
+
+                       end += _offset;
+                       start += _offset;
+
+                       for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
+                               uint v;
+                               if (next == 8)
+                                       v = _val1;
+                               else if (next == 16)
+                                       v = _val2;
+                               else if (next == 24)
+                                       v = _val3;
+                               else if (next == 32)
+                                       v = _val4;
+                               else
+                                       v = 0;
+                               v >>= (start & 0x7) << 2;
+                               if (next > end)
+                                       next = end;
+
+                               _cbuf [--i] = (char)('0' | v & 0xf);
+                               switch (next - start) {
+                               case 8:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 7;
+                               case 7:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 6;
+                               case 6:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 5;
+                               case 5:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 4;
+                               case 4:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 3;
+                               case 3:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 2;
+                               case 2:
+                                       _cbuf [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 1;
+                               case 1:
+                                       if (next == end)
+                                               return;
+                                       continue;
                                }
                        }
-                       public bool ZeroOnly {
-                               get {
-                                       for (int i = 0; i < _digits.Length; i++)
-                                               if (_digits [i] != 0)
-                                                       return false;
-                                       return true;
+               }
+
+               private void AppendDigits (int start, int end, StringBuilder sb)
+               {
+                       if (start >= end)
+                               return;
+
+                       int i = sb.Length + (end - start);
+                       sb.Length = i;
+
+                       end += _offset;
+                       start += _offset;
+
+                       for (int next = start + 8 - (start & 0x7); ; start = next, next += 8) {
+                               uint v;
+                               if (next == 8)
+                                       v = _val1;
+                               else if (next == 16)
+                                       v = _val2;
+                               else if (next == 24)
+                                       v = _val3;
+                               else if (next == 32)
+                                       v = _val4;
+                               else
+                                       v = 0;
+                               v >>= (start & 0x7) << 2;
+                               if (next > end)
+                                       next = end;
+                               sb [--i] = (char)('0' | v & 0xf);
+                               switch (next - start) {
+                               case 8:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 7;
+                               case 7:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 6;
+                               case 6:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 5;
+                               case 5:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 4;
+                               case 4:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 3;
+                               case 3:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 2;
+                               case 2:
+                                       sb [--i] = (char)('0' | (v >>= 4) & 0xf);
+                                       goto case 1;
+                               case 1:
+                                       if (next == end)
+                                               return;
+                                       continue;
                                }
                        }
-                       #endregion
+               }
 
-                       #region Public Method
+               #endregion Append helpers
 
-                       #region Round
-                       public bool RoundPos (int pos)
-                       {
-                               return RoundPos (pos, true);
-                       }
-                       public bool RoundPos (int pos, bool carryFive)
-                       {
-                               bool carry = false;
+               #region others
 
-                               if (_decPointPos <= 0)
-                                       pos = pos - _decPointPos - 1;
+               private void Multiply10(int count)
+               {
+                       if (count <= 0 || _digitsLen == 0)
+                               return;
 
-                               if (pos >= _digits.Length)
-                                       return false;
+                       _decPointPos += count;
+               }
 
-                               if (pos < 0) {
-                                       _digits = new byte [1];
-                                       _digits [0] = 0;
-                                       _decPointPos = 1;
-                                       _positive = true;
-                                       return false;
-                               }
+               private void Divide10(int count)
+               {
+                       if (count <= 0 || _digitsLen == 0)
+                               return;
 
-                               for (int i = pos; i >= 0; i--) {
-                                       RoundHelper (i, carryFive, ref carry);
-                                       if (!carry)
-                                               break;
-                               }
+                       _decPointPos -= count;
+               }
 
-                               if (carry) {
-                                       byte[] temp = new byte [_digits.Length + 1];
-                                       _digits.CopyTo (temp, 1);
-                                       temp [0] = 1;
-                                       _digits = temp;
-                                       _decPointPos ++;
-                                       pos ++;
-                               }
+               private NumberFormatter GetClone ()
+               {
+                       return (NumberFormatter)this.MemberwiseClone ();
+               }
 
-                               for (int i = pos; i < _digits.Length; i++)
-                                       _digits [i] = 0;
-                               TrimDecimalEndZeros ();
+               #endregion others
 
-                               return carry;
-                       }
-                       public bool RoundDecimal (int decimals)
-                       {
-                               return RoundDecimal (decimals, true, true);
-                       }
-                       public bool RoundDecimal (int decimals, bool carryFive, bool countZero)
+               #region custom
+
+               private class CustomInfo
+               {
+                       public bool UseGroup = false;
+                       public int DecimalDigits = 0;
+                       public int DecimalPointPos = -1;
+                       public int DecimalTailSharpDigits = 0;
+                       public int IntegerDigits = 0;
+                       public int IntegerHeadSharpDigits = 0;
+                       public int IntegerHeadPos = 0;
+                       public bool UseExponent = false;
+                       public int ExponentDigits = 0;
+                       public int ExponentTailSharpDigits = 0;
+                       public bool ExponentNegativeSignOnly = true;
+                       public int DividePlaces = 0;
+                       public int Percents = 0;
+                       public int Permilles = 0;
+
+                       public static void GetActiveSection (string format, ref bool positive, bool zero, ref int offset, ref int length)
                        {
-                               bool carry = false;
+                               int[] lens = new int [3];
+                               int index = 0;
+                               int lastPos = 0;
+                               bool quoted = false;
 
-                               if (countZero || (_decPointPos > 0))
-                                       decimals += _decPointPos;
+                               for (int i = 0; i < format.Length; i++) {
+                                       char c = format [i];
 
-                               if (!HasDecimal || decimals >= _digits.Length)
-                                       return false;
+                                       if (c == '\"' || c == '\'') {
+                                               if (i == 0 || format [i - 1] != '\\')
+                                                       quoted = !quoted;
 
-                               if (decimals < 0) {
-                                       _digits = new byte [1];
-                                       _digits [0] = 0;
-                                       _decPointPos = 1;
-                                       _positive = true;
-                                       return false;
-                               }
+                                               continue;
+                                       }
 
-                               for (int i = decimals; i >= 0; i--) {
-                                       RoundHelper (i, carryFive, ref carry);
-                                       if (!carry)
-                                               break;
+                                       if (c == ';' && !quoted && (i == 0 || format [i - 1] != '\\')) {
+                                               lens [index++] = i - lastPos;
+                                               lastPos = i + 1;
+                                               if (index == 3)
+                                                       break;
+                                       }
                                }
 
-                               if (carry) {
-                                       byte[] temp = new byte [_digits.Length + 1];
-                                       _digits.CopyTo (temp, 1);
-                                       temp [0] = 1;
-                                       _digits = temp;
-                                       _decPointPos ++;
-                                       decimals ++;
+                               if (index == 0) {
+                                       offset = 0;
+                                       length = format.Length;
+                                       return;
                                }
-
-                               for (int i = decimals; i < _digits.Length; i++)
-                                       _digits [i] = 0;
-                               TrimDecimalEndZeros ();
-
-                               return carry;
-                       }
-                       void RoundHelper (int index, bool carryFive, ref bool carry)
-                       {
-                               if (carry) {
-                                       if (_digits [index] == 9) {
-                                               carry = true;
-                                               _digits [index] = 0;
-                                       } else {
-                                               carry = false;
-                                               _digits [index] ++;
+                               if (index == 1) {
+                                       if (positive || zero) {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
+                                       }
+                                       if (lens [0] + 1 < format.Length) {
+                                               positive = true;
+                                               offset = lens [0] + 1;
+                                               length = format.Length - offset;
+                                               return;
+                                       }
+                                       else {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
                                        }
-                               } else if (_digits [index] >= (carryFive ? 5 : 6)) {
-                                       carry = true;
                                }
+                               if (index == 2) {
+                                       if (zero) {
+                                               offset = lens [0] + lens [1] + 2;
+                                               length = format.Length - offset;
+                                               return;
+                                       }
+                                       if (positive) {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
+                                       }
+                                       if (lens [1] > 0) {
+                                               positive = true;
+                                               offset = lens [0] + 1;
+                                               length = lens [1];
+                                               return;
+                                       }
+                                       else {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
+                                       }
+                               }
+                               if (index == 3) {
+                                       if (zero) {
+                                               offset = lens [0] + lens [1] + 2;
+                                               length = lens [2];
+                                               return;
+                                       }
+                                       if (positive) {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
+                                       }
+                                       if (lens [1] > 0) {
+                                               positive = true;
+                                               offset = lens [0] + 1;
+                                               length = lens [1];
+                                               return;
+                                       }
+                                       else {
+                                               offset = 0;
+                                               length = lens [0];
+                                               return;
+                                       }
+                               }
+
+                               throw new ArgumentException ();
                        }
-                       public bool RoundEffectiveDigits (int digits)
-                       {
-                               return RoundEffectiveDigits (digits, true, true);
-                       }
-                       public bool RoundEffectiveDigits (int digits, bool carryFive, bool carryEven)
+
+                       public static CustomInfo Parse (string format, int offset, int length, NumberFormatInfo nfi)
                        {
-                               bool carry = false;
+                               char literal = '\0';
+                               bool integerArea = true;
+                               bool decimalArea = false;
+                               bool exponentArea = false;
+                               bool sharpContinues = true;
 
-                               if (digits >= _digits.Length || digits < 0)
-                                       return false;
+                               CustomInfo info = new CustomInfo ();
+                               int groupSeparatorCounter = 0;
 
-                               if (digits + 1 < _digits.Length && _digits [digits + 1] == 5 && _digits [digits] % 2 == (carryEven ? 0 : 1))
-                                       carryFive = false;
-
-                               /// are we cutting from the maximum precision ?
-                               if (_digits.Length == _defMaxPrecision) {
-                                       // special case if we *aren't* cutting inside the extra precision (e.g. 16 on 17)
-                                       if (digits != _defMaxPrecision - 1) {
-                                               // ok, here we look at the *two* extra numbers we're keeping
-                                               // (we keep 17 digits while the true precision is 15 digits).
-                                               int extra = _digits[_defMaxPrecision - 2] * 10 + _digits[_defMaxPrecision - 1];
-                                               carry = (extra >= 50);
-                                               if (carry) {
-                                                       _digits[_defMaxPrecision - 2] = 0;
-                                                       _digits[_defMaxPrecision - 1] = 0;
-                                                       int d = _digits.Length - 3;
-                                                       CarryPropagation (ref d, carryFive, ref carry);
-                                               }
+                               for (int i = offset; i - offset < length; i++) {
+                                       char c = format [i];
+
+                                       if (c == literal && c != '\0') {
+                                               literal = '\0';
+                                               continue;
                                        }
-                               }
-                               CarryPropagation (ref digits, carryFive, ref carry);
+                                       if (literal != '\0')
+                                               continue;
 
-                               for (int i = digits; i < _digits.Length; i++)
-                                       _digits [i] = 0;
-                               TrimDecimalEndZeros ();
+                                       if (exponentArea && (c != '\0' && c != '0' && c != '#')) {
+                                               exponentArea = false;
+                                               integerArea = (info.DecimalPointPos < 0);
+                                               decimalArea = !integerArea;
+                                               i--;
+                                               continue;
+                                       }
 
-                               return carry;
-                       }
+                                       switch (c) {
+                                       case '\\':
+                                               i++;
+                                               continue;
+                                       case '\'':
+                                       case '\"':
+                                               if (c == '\"' || c == '\'') {
+                                                       literal = c;
+                                               }
+                                               continue;
+                                       case '#':
+                                               if (sharpContinues && integerArea)
+                                                       info.IntegerHeadSharpDigits++;
+                                               else if (decimalArea)
+                                                       info.DecimalTailSharpDigits++;
+                                               else if (exponentArea)
+                                                       info.ExponentTailSharpDigits++;
+
+                                               goto case '0';
+                                       case '0':
+                                               if (c != '#') {
+                                                       sharpContinues = false;
+                                                       if (decimalArea)
+                                                               info.DecimalTailSharpDigits = 0;
+                                                       else if (exponentArea)
+                                                               info.ExponentTailSharpDigits = 0;
+                                               }
+                                               if (info.IntegerHeadPos == -1)
+                                                       info.IntegerHeadPos = i;
 
-                       private void CarryPropagation (ref int digits, bool carryFive, ref bool carry)
-                       {
-                               for (int i = digits; i >= 0; i--) {
-                                       RoundHelper (i, carryFive, ref carry);
-                                       if (!carry)
+                                               if (integerArea) {
+                                                       info.IntegerDigits++;
+                                                       if (groupSeparatorCounter > 0)
+                                                               info.UseGroup = true;
+                                                       groupSeparatorCounter = 0;
+                                               }
+                                               else if (decimalArea)
+                                                       info.DecimalDigits++;
+                                               else if (exponentArea)
+                                                       info.ExponentDigits++;
                                                break;
-                               }
-
-                               if (carry) {
-                                       byte[] temp = new byte[_digits.Length + 1];
-                                       _digits.CopyTo (temp, 1);
-                                       temp[0] = 1;
-                                       _digits = temp;
-                                       _decPointPos++;
-                                       digits++;
-                               }
-                       }
+                                       case 'e':
+                                       case 'E':
+                                               if (info.UseExponent)
+                                                       break;
 
-                       #endregion
+                                               info.UseExponent = true;
+                                               integerArea = false;
+                                               decimalArea = false;
+                                               exponentArea = true;
+                                               if (i + 1 - offset < length) {
+                                                       char nc = format [i + 1];
+                                                       if (nc == '+')
+                                                               info.ExponentNegativeSignOnly = false;
+                                                       if (nc == '+' || nc == '-')
+                                                               i++;
+                                                       else if (nc != '0' && nc != '#') {
+                                                               info.UseExponent = false;
+                                                               if (info.DecimalPointPos < 0)
+                                                                       integerArea = true;
+                                                       }
+                                               }
 
-                       #region Trim
-                       public void TrimDecimalEndZeros ()
-                       {
-                               int len = 0;
-                               for (int i = _digits.Length - 1; i >= 0; i --) {
-                                       if (_digits [i] != 0)
                                                break;
-                                       len ++;
-                               }
-
-                               if (len > 0) {
-                                       byte[] temp = new byte [_digits.Length - len];
-                                       Array.Copy (_digits, 0, temp, 0, temp.Length);
-                                       _digits = temp;
-                               }
-                       }
-                       public void TrimIntegerStartZeros ()
-                       {
-                               if (_decPointPos < 0 && _decPointPos >= _digits.Length)
-                                       return;
-
-                               int len = 0;
-                               for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
-                                       if (_digits [i] != 0)
+                                       case '.':
+                                               integerArea = false;
+                                               decimalArea = true;
+                                               exponentArea = false;
+                                               if (info.DecimalPointPos == -1)
+                                                       info.DecimalPointPos = i;
                                                break;
-                                       len ++;
-                               }
-
-                               if (len == _decPointPos)
-                                       len --;
-
-                               if (len == _digits.Length) {
-                                       _digits = new byte [1];
-                                       _digits [0] = 0;
-                                       _decPointPos = 1;
-                                       _positive = true;
-                               } else if (len > 0) {
-                                       byte[] temp = new byte [_digits.Length - len];
-                                       Array.Copy (_digits, len, temp, 0, temp.Length);
-                                       _digits = temp;
-                                       _decPointPos -= len;
+                                       case '%':
+                                               info.Percents++;
+                                               break;
+                                       case '\u2030':
+                                               info.Permilles++;
+                                               break;
+                                       case ',':
+                                               if (integerArea && info.IntegerDigits > 0)
+                                                       groupSeparatorCounter++;
+                                               break;
+                                       default:
+                                               break;
+                                       }
                                }
-                       }
 
-                       #endregion
+                               if (info.ExponentDigits == 0)
+                                       info.UseExponent = false;
+                               else
+                                       info.IntegerHeadSharpDigits = 0;
 
-                       #region Integer
-                       public void AppendIntegerString (int minLength, StringBuilder cb)
-                       {
-                               if (IntegerDigits == 0) {
-                                       cb.Append ('0', minLength);
-                                       return;
-                               }
-                               if (_decPointPos <= 0) {
-                                       cb.Append ('0', minLength);
-                                       return;
-                               }
+                               if (info.DecimalDigits == 0)
+                                       info.DecimalPointPos = -1;
 
-                               if (_decPointPos < minLength)
-                                       cb.Append ('0', minLength - _decPointPos);
+                               info.DividePlaces += groupSeparatorCounter * 3;
 
-                               for (int i = 0; i < _decPointPos; i++) {
-                                       if (i < _digits.Length)
-                                               cb.Append ((char)('0' + _digits [i]));
-                                       else
-                                               cb.Append ('0');
-                               }
+                               return info;
                        }
-                       public void AppendIntegerStringWithGroupSeparator (StringBuilder sb, int[] groups, string groupSeparator)
-                       {
-                               if (_decPointPos <= 0) {
-                                       sb.Append ('0');
-                                       return;
-                               }
 
-                               int intLen = IntegerDigits;
-                               int total = 0;
-                               int groupIndex = 0;
-                               for (int i = 0; i < groups.Length; i++) {
-                                       total += groups [i];
-                                       if (total <= intLen)
-                                               groupIndex = i;
-                               }
+                       public string Format (string format, int offset, int length, NumberFormatInfo nfi, bool positive, StringBuilder sb_int, StringBuilder sb_dec, StringBuilder sb_exp)
+                       {
+                               StringBuilder sb = new StringBuilder ();
+                               char literal = '\0';
+                               bool integerArea = true;
+                               bool decimalArea = false;
+                               int intSharpCounter = 0;
+                               int sb_int_index = 0;
+                               int sb_dec_index = 0;
 
-                               if (groups.Length > 0 && total > 0) {
-                                       int counter;
-                                       int groupSize = groups [groupIndex];
+                               int[] groups = nfi.RawNumberGroupSizes;
+                               string groupSeparator = nfi.NumberGroupSeparator;
+                               int intLen = 0, total = 0, groupIndex = 0, counter = 0, groupSize = 0;
+                               if (UseGroup && groups.Length > 0) {
+                                       intLen = sb_int.Length;
+                                       for (int i = 0; i < groups.Length; i++) {
+                                               total += groups [i];
+                                               if (total <= intLen)
+                                                       groupIndex = i;
+                                       }
+                                       groupSize = groups [groupIndex];
                                        int fraction = intLen > total ? intLen - total : 0;
                                        if (groupSize == 0) {
                                                while (groupIndex >= 0 && groups [groupIndex] == 0)
-                                                       groupIndex --;
-                                               
+                                                       groupIndex--;
+
                                                groupSize = fraction > 0 ? fraction : groups [groupIndex];
                                        }
-                                       if (fraction == 0) {
+                                       if (fraction == 0)
                                                counter = groupSize;
-                                       else {
+                                       else {
                                                groupIndex += fraction / groupSize;
                                                counter = fraction % groupSize;
                                                if (counter == 0)
                                                        counter = groupSize;
                                                else
-                                                       groupIndex ++;
-                                       }
-                                       
-                                       for (int i = 0; i < _decPointPos; i++) {
-                                               if (i < _digits.Length) {
-                                                       sb.Append ((char)('0' + _digits [i]));
-                                               } else {
-                                                       sb.Append ('0');
-                                               }
-
-                                               if (i < intLen - 1 && --counter == 0) {
-                                                       sb.Append (groupSeparator);
-                                                       if (--groupIndex < groups.Length && groupIndex >= 0)
-                                                               groupSize = groups [groupIndex];
-                                                       counter = groupSize;
-                                               }
-                                       }
-                               } else {
-                                       for (int i = 0; i < _decPointPos; i++) {
-                                               if (i < _digits.Length) {
-                                                       sb.Append ((char)('0' + _digits [i]));
-                                               } else {
-                                                       sb.Append ('0');
-                                               }
+                                                       groupIndex++;
                                        }
                                }
-                       }
-                       #endregion
+                               else
+                                       UseGroup = false;
 
-                       #region Decimal
-                       public string GetDecimalString (int precision)
-                       {
-                               if (!HasDecimal)
-                                       return new string ('0', precision);
+                               for (int i = offset; i - offset < length; i++) {
+                                       char c = format [i];
 
-                               StringBuilder sb = new StringBuilder (precision);
-                               for (int i = _decPointPos; i < _digits.Length && i < precision + _decPointPos; i++) {
-                                       if (i >= 0)
-                                               sb.Append ((char)('0' + _digits [i]));
-                                       else
-                                               sb.Append ('0');
-                               }
-                               if (sb.Length < precision)
-                                       sb.Append ('0', precision - sb.Length);
-                               else if (sb.Length > precision)
-                                       sb.Remove (0, precision);
-                               return sb.ToString ();
-                       }
+                                       if (c == literal && c != '\0') {
+                                               literal = '\0';
+                                               continue;
+                                       }
+                                       if (literal != '\0') {
+                                               sb.Append (c);
+                                               continue;
+                                       }
 
-                       public void AppendDecimalString (int precision, StringBuilder cb)
-                       {
-                               if (!HasDecimal) {
-                                       cb.Append ('0', precision);
-                                       return;
-                               }
+                                       switch (c) {
+                                       case '\\':
+                                               i++;
+                                               if (i - offset < length)
+                                                       sb.Append (format [i]);
+                                               continue;
+                                       case '\'':
+                                       case '\"':
+                                               if (c == '\"' || c == '\'')
+                                                       literal = c;
+                                               continue;
+                                       case '#':
+                                               goto case '0';
+                                       case '0':
+                                               if (integerArea) {
+                                                       intSharpCounter++;
+                                                       if (IntegerDigits - intSharpCounter < sb_int.Length + sb_int_index || c == '0')
+                                                               while (IntegerDigits - intSharpCounter + sb_int_index < sb_int.Length) {
+                                                                       sb.Append (sb_int [sb_int_index++]);
+                                                                       if (UseGroup && --intLen > 0 && --counter == 0) {
+                                                                               sb.Append (groupSeparator);
+                                                                               if (--groupIndex < groups.Length && groupIndex >= 0)
+                                                                                       groupSize = groups [groupIndex];
+                                                                               counter = groupSize;
+                                                                       }
+                                                               }
+                                                       break;
+                                               }
+                                               else if (decimalArea) {
+                                                       if (sb_dec_index < sb_dec.Length)
+                                                               sb.Append (sb_dec [sb_dec_index++]);
+                                                       break;
+                                               }
 
-                               int i = _decPointPos;
-                               for (; i < _digits.Length && i < precision + _decPointPos; i++) {
-                                       if (i >= 0)
-                                               cb.Append ((char)('0' + _digits [i]));
-                                       else
-                                               cb.Append ('0');
-                               }
+                                               sb.Append (c);
+                                               break;
+                                       case 'e':
+                                       case 'E':
+                                               if (sb_exp == null || !UseExponent) {
+                                                       sb.Append (c);
+                                                       break;
+                                               }
 
-                               i -= _decPointPos;
-                               if (i < precision)
-                                       cb.Append ('0', precision - i);
-                       }
-                       #endregion
+                                               bool flag1 = true;
+                                               bool flag2 = false;
 
-                       #region others
-                       public bool CheckZeroOnlyInteger ()
-                       {
-                               for (int i = 0; i < _decPointPos && i < _digits.Length; i++) {
-                                       if (_digits [i] != 0)
-                                               return false;
-                               }
-                               return true;
-                       }
-                       public void Multiply10 (int count)
-                       {
-                               if (count <= 0)
-                                       return;
+                                               int q;
+                                               for (q = i + 1; q - offset < length; q++) {
+                                                       if (format [q] == '0') {
+                                                               flag2 = true;
+                                                               continue;
+                                                       }
+                                                       if (q == i + 1 && (format [q] == '+' || format [q] == '-'))
+                                                               continue;
+                                                       if (!flag2)
+                                                               flag1 = false;
+                                                       break;
+                                               }
 
-                               _decPointPos += count;
+                                               if (flag1) {
+                                                       i = q - 1;
+                                                       integerArea = (DecimalPointPos < 0);
+                                                       decimalArea = !integerArea;
 
-                               TrimIntegerStartZeros ();
-                       }
-                       public void Divide10 (int count)
-                       {
-                               if (count <= 0)
-                                       return;
+                                                       sb.Append (c);
+                                                       sb.Append (sb_exp);
+                                                       sb_exp = null;
+                                               }
+                                               else
+                                                       sb.Append (c);
 
-                               _decPointPos -= count;
-                       }
-                       public override string ToString()
-                       {
-                               StringBuilder sb = new StringBuilder ();
-                               AppendIntegerString (IntegerDigits, sb);
-                               if (HasDecimal) {
-                                       sb.Append ('.');
-                                       AppendDecimalString (DecimalDigits, sb);
+                                               break;
+                                       case '.':
+                                               if (DecimalPointPos == i) {
+                                                       if (DecimalDigits > 0) {
+                                                               while (sb_int_index < sb_int.Length)
+                                                                       sb.Append (sb_int [sb_int_index++]);
+                                                       }
+                                                       if (sb_dec.Length > 0)
+                                                               sb.Append (nfi.NumberDecimalSeparator);
+                                               }
+                                               integerArea = false;
+                                               decimalArea = true;
+                                               break;
+                                       case ',':
+                                               break;
+                                       case '%':
+                                               sb.Append (nfi.PercentSymbol);
+                                               break;
+                                       case '\u2030':
+                                               sb.Append (nfi.PerMilleSymbol);
+                                               break;
+                                       default:
+                                               sb.Append (c);
+                                               break;
+                                       }
                                }
-                               return sb.ToString ();
-                       }
-                       public char GetChar (int pos)
-                       {
-                               if (_decPointPos <= 0)
-                                       pos += _decPointPos - 1;
-                               
-                               if (pos < 0 || pos >= _digits.Length)
-                                       return '0';
-                               else
-                                       return (char)('0' + _digits [pos]);
-                       }
-                       public byte GetDigitByte (int pos)
-                       {
-                               if (_decPointPos <= 0)
-                                       pos += _decPointPos - 1;
-                               
-                               if (pos < 0 || pos >= _digits.Length)
-                                       return 0;
-                               else
-                                       return _digits [pos];
-                       }
-                       public NumberStore GetClone ()
-                       {
-                               NumberStore ns = new NumberStore ();
-
-                               ns._decPointPos = this._decPointPos;
-                               ns._defMaxPrecision = this._defMaxPrecision;
-                               ns._defPrecision = this._defPrecision;
-                               ns._digits = (byte[])this._digits.Clone ();
-                               ns._infinity = this._infinity;
-                               ns._NaN = this._NaN;
-                               ns._positive = this._positive;
-
-                               return ns;
-                       }
-                       public int GetDecimalPointPos ()
-                       {
-                               return _decPointPos;
-                       }
-                       public void SetDecimalPointPos (int dp)
-                       {
-                               _decPointPos = dp;
-                       }
-                       #endregion
 
-                       #endregion
+                               if (!positive)
+                                       sb.Insert (0, nfi.NegativeSign);
 
-                       #region Public Static Method
-                       public static bool IsZeroOnly (StringBuilder sb)
-                       {
-                               for (int i = 0; i < sb.Length; i++)
-                                       if (char.IsDigit (sb [i]) && sb [i] != '0')
-                                               return false;
-                               return true;
-                       }
-                       public static void AppendIntegerStringFromUInt32 (StringBuilder sb, uint v)
-                       {
-                               if (v < 0)
-                                       throw new ArgumentException ();
-
-                               int i = 9;
-
-                               if (v >= 1000000000)
-                                       i = 9;
-                               else if (v >= 100000000)
-                                       i = 8;
-                               else if (v >= 10000000)
-                                       i = 7;
-                               else if (v >= 1000000)
-                                       i = 6;
-                               else if (v >= 100000)
-                                       i = 5;
-                               else if (v >= 10000)
-                                       i = 4;
-                               else if (v >= 1000)
-                                       i = 3;
-                               else if (v >= 100)
-                                       i = 2;
-                               else if (v >= 10)
-                                       i = 1;
-                               else
-                                       i = 0;
-                               do {
-                                       uint n = v / IntList [i];
-                                       sb.Append (NumberFormatter.digitLowerTable [n]);
-                                       v -= IntList [i--] * n;
-                               } while (i >= 0);
+                               return sb.ToString ();
                        }
-                       #endregion
                }
+
                #endregion
        }
 }