Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

String format numbers to millions, thousands with rounding

Tags:

c#

.net

currency

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.

like image 236
RPM1984 Avatar asked May 12 '15 02:05

RPM1984


People also ask

How do you format numbers in thousands or millions?

Follow These Steps. Click the ribbon Home, right-click on the cell, then expand the default to show “Format Cells” dialog. In the Format Cells dialog box, on the Number tab, select Custom, then enter #,, “Million” where it says General. (Note: there is a space between the second comma and the double quotation mark.)


3 Answers

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");
      }
   }
like image 166
RenniePet Avatar answered Oct 23 '22 04:10

RenniePet


This is my code with test outputs

1249            1.24K
12499           12.4K
124999          124K
1249999         1.24M
12499999        12.4M
124999999       124M
1249999999      1.24B

The code will output three digits at maximum.

    static string FormatNumber(uint n)
    {
        if (n < 1000)
            return n.ToString();

        if (n < 10000)
            return String.Format("{0:#,.##}K", n - 5);

        if (n < 100000)
            return String.Format("{0:#,.#}K", n - 50);

        if (n < 1000000)
            return String.Format("{0:#,.}K", n - 500);

        if (n < 10000000)
            return String.Format("{0:#,,.##}M", n - 5000);

        if (n < 100000000)
            return String.Format("{0:#,,.#}M", n - 50000);

        if (n < 1000000000)
            return String.Format("{0:#,,.}M", n - 500000);

        return String.Format("{0:#,,,.##}B", n - 5000000);
    }
like image 12
CS Pei Avatar answered Oct 23 '22 05:10

CS Pei


Since the format essentially changes based on the range you'll most likely need some conditional formatting similar to below. I have only tested the sample set provided, so make sure this works for the full range of expected values.

class Program
{
    static void Main(String[] args)
    {
        Console.WriteLine(RoundAndFormat(1));
        Console.WriteLine(RoundAndFormat(10));
        Console.WriteLine(RoundAndFormat(100));
        Console.WriteLine(RoundAndFormat(1000));
        Console.WriteLine(RoundAndFormat(100000));
        Console.WriteLine(RoundAndFormat(125000));
        Console.WriteLine(RoundAndFormat(125900));
        Console.WriteLine(RoundAndFormat(1000000));
        Console.WriteLine(RoundAndFormat(1250000));
        Console.WriteLine(RoundAndFormat(1258000));
        Console.WriteLine(RoundAndFormat(10000000));
        Console.WriteLine(RoundAndFormat(10500000));
        Console.WriteLine(RoundAndFormat(100000000));
        Console.WriteLine(RoundAndFormat(100100000));

        Console.ReadLine();
    }

    public static String RoundAndFormat(Int32 value)
    {
        var result = String.Empty;
        var negative = value < 0;
        if (negative) value = value * -1;

        if (value < 1000)
        {
            result = value.ToString();
        }
        else if (value < 1000000)
        {
            result = RoundDown(value / 1000.0, 0) + "K";
        }
        else if (value < 100000000)
        {
            result = RoundDown(value / 1000000.0, 2) + "M";
        }
        else if (value < 10000000000)
        {
            result = RoundDown(value / 1000000.0, 0) + "M";
        }

        if (negative) return "-" + result;
        return result;
    }

    public static Double RoundDown(Double value, Int32 digits)
    {
        var pow = Math.Pow(10, digits);
        return Math.Truncate(value * pow) / pow;
    }
like image 4
TMS Avatar answered Oct 23 '22 05:10

TMS