Search code examples
c#.netcurrency

String format numbers to millions, thousands with rounding


I'm trying to format a price for display, and I want to display a number with the million (M) or thousands (K) suffix, but only ever display at most 3 values, rounded down.

I found this question which is very close to what I want, but doesn't handle rounding (specifically, always rounding down)

Likewise, with this question you have no control over the rounding.

Sample input/expected output:

1 = 1
10 = 10
100 = 100
1000 = 1K
100000 = 100K
125000 = 125K
125900 = 125K
1000000 = 1M
1250000 = 1.25M
1258000 = 1.25M
10000000 = 10M
10500000 = 10.5M
100000000 = 100M
100100000 = 100M

I essentially only ever want to display 3 values.

I can't see how i can use the "," custom specifier and specify rounding.

My initial thinking suggests I need to use a combination of the above, Math.Floor and some .ToString() formatting magic, but i'm not really sure where to start.

Can someone help me out?

Thanks in advance.


Solution

  • This should help, combined with one of the formatting techniques in the other questions you've linked to.

      internal long MaxThreeSignificantDigits(long x)
      {
         int i = (int)Math.Log10(x);
         i = Math.Max(0, i - 2);
         i = (int)Math.Pow(10, i);
         return x / i * i;
      }
    

    EDIT:

    OK, how about this?

     Console.WriteLine(SO30180672.FormatNumber(1));
     Console.WriteLine(SO30180672.FormatNumber(12));
     Console.WriteLine(SO30180672.FormatNumber(123));
     Console.WriteLine(SO30180672.FormatNumber(1234));
     Console.WriteLine(SO30180672.FormatNumber(12345));
     Console.WriteLine(SO30180672.FormatNumber(123456));
     Console.WriteLine(SO30180672.FormatNumber(1234567));
     Console.WriteLine(SO30180672.FormatNumber(12345678));
     Console.WriteLine(SO30180672.FormatNumber(123456789));
    

    Following is partially copied from here: https://stackoverflow.com/a/23384710/253938

       internal class SO30180672
       {
          internal static string FormatNumber(long num)
          {
             num = MaxThreeSignificantDigits(num);
    
             if (num >= 100000000)
                return (num / 1000000D).ToString("0.#M");
             if (num >= 1000000)
                return (num / 1000000D).ToString("0.##M");
             if (num >= 100000)
                return (num / 1000D).ToString("0k");
             if (num >= 100000)
                return (num / 1000D).ToString("0.#k");
             if (num >= 1000)
                return (num / 1000D).ToString("0.##k");
             return num.ToString("#,0");
          }
    
    
          internal static long MaxThreeSignificantDigits(long x)
          {
             int i = (int)Math.Log10(x);
             i = Math.Max(0, i - 2);
             i = (int)Math.Pow(10, i);
             return x / i * i;
          }
       }
    

    EDIT 2 - thank you very much to @Rhexis

       internal class SO30180672
       {
          internal static void RunTest()
          {
             Console.WriteLine(FormatNumber(1));
             Console.WriteLine(FormatNumber(10));
             Console.WriteLine(FormatNumber(100));
             Console.WriteLine(FormatNumber(1000));
             Console.WriteLine(FormatNumber(10000));
             Console.WriteLine(FormatNumber(100000));
             Console.WriteLine(FormatNumber(125000));
             Console.WriteLine(FormatNumber(125900));
             Console.WriteLine(FormatNumber(1000000));
             Console.WriteLine(FormatNumber(1250000));
             Console.WriteLine(FormatNumber(1258000));
             Console.WriteLine(FormatNumber(10000000));
             Console.WriteLine(FormatNumber(10500000));
             Console.WriteLine(FormatNumber(100000000));
             Console.WriteLine(FormatNumber(100100000));
          }
    
          private static string FormatNumber(long num)
          {
             // Ensure number has max 3 significant digits (no rounding up can happen)
             long i = (long)Math.Pow(10, (int)Math.Max(0, Math.Log10(num) - 2));
             num = num / i * i;
    
             if (num >= 1000000000)
                return (num / 1000000000D).ToString("0.##") + "B";
             if (num >= 1000000)
                return (num / 1000000D).ToString("0.##") + "M";
             if (num >= 1000)
                return (num / 1000D).ToString("0.##") + "K";
    
             return num.ToString("#,0");
          }
       }