Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Format decimal number with digit grouping and limit the number of digits

Basically I'm trying to perform number formatting in the exact same way as the Windows calculator does. Hence, my requirements are:

  • Limit the number of displayed digits to a maximum (e.g. 16). I was able to accomplish that using number.ToString("G16").
  • Add digit grouping to the number. I was able to accomplish that using: number.ToString(String.Format("#,0.{0};-#,0.{0}", New String("#"c, 15)))

Any ideas on how to combine these together to get the same behavior as Windows calculator?


Some examples with the desired output:

Examples


I added an answer below which I would be using if the desired output can't be achieved using one string formatting. Feel free to suggest any optimizations/changes to that answer if you believe no direct way to achieve this (which is my original requirement)

Sorry if I caused some kind of confusion to anyone. I just thought that there might be a simple one string formatting to achieve this and I was -and still am- curious to find out if that's true.

like image 975
41686d6564 stands w. Palestine Avatar asked Dec 06 '16 22:12

41686d6564 stands w. Palestine


People also ask

How do you set decimal places in Java?

Using the format() method "%. 2f" denotes 2 decimal places, "%. 3f" denotes 3 decimal places, and so on.

Where is number group in Word?

On the Home tab, in the Paragraph group, click Numbering. Note: To select a different number format, right-click a number in the list, point to Numbering, click Define New Number Format, and then select the options that you want.


3 Answers

After a lot of search on this issue. You cannot perform this with a single format because you are asking about an IF .. ELSE LOGIC not for a one-way formatting (performing two formatting on a number)

IF d.ToString("G16") contains scientific notation

    ... do something

ELSE

    ... group digits

So you have to use an IF to achieve this

Str = If( num.ToString("G15").Contains("e"), num.ToString("G15"), num.ToString(String.Format("#,0.{0};-#,0.{0}", New String("#"c, 15))))

Update1

Based on your update use the following

Public Function FormatDouble(ByVal dbl As Double, ByVal len As Integer) As String

    Return Double.Parse(dbl.ToString("G" & len)).ToString("#,#.#".PadRight(len, "#"), System.Globalization.CultureInfo.InvariantCulture)

End Function
  • dbl.ToString("G" &len) is formatting dbl to a fixed length = len

  • Double.parse is converting the result again to double with the new length. Note: if th result contains e it will be removed after parse

  • ToString("#,#.#".PadRight(len, "#"), System.Globalization.CultureInfo.InvariantCulture) is adding Group digits to the resulted double

Note

When providing length ("G15") it will round the number to it. It may reduce length from decimal part but it doesn't from the integers it will round the number to the specified length. I.e. 1734.Tostring("G1") will returns 2000 but not 2 / 1734.Tostring("G2") will returns 1700 but not 17

If you want to reduce numbers you have to use String Functions like Substring And Left after the Tostring("G1")

Hope it helps

like image 77
Hadi Avatar answered Sep 22 '22 16:09

Hadi


I don't know an easy way to do that in the way you are looking for.

But being a curious sort of fellow I did wonder how it could be achieved using only string methods.

To be clear, I'm not advocating this approach as a good solution - it's rather hard to understand in one line, but hey, an interesting exercise for me.

If you felt like doing it in one horrendous line (c#):

var num1 = 123123123.456456456;  // result: 123,123,123.4564565
//var num1 = 123123123456456456.78;  // result: 1.231231234564565E+17
//var num1 = 123123123456; // result: 1,231,231,234,564,564
//var num1 = 1231231; // result: 1,231,231

Console.WriteLine(long.Parse((num1.ToString("G16") + ".").Substring(0, (num1.ToString("G16") + ".").IndexOf('.'))).ToString("N0") + (num1.ToString("G16") + ".").Substring((num1.ToString("G16") + ".").IndexOf('.'), (num1.ToString("G16") + ".").LastIndexOf('.')- (num1.ToString("G16") + ".").IndexOf('.')));

Otherwise broken up a little; it's a little clearer what approach I'm taking:

var num1 = 123123123.456456456;
var num1a = num1.ToString("G16") + "."; 

Console.WriteLine(long.Parse(num1a.Substring(0, num1a.IndexOf('.'))).ToString("N0") + num1a.Substring(num1a.IndexOf('.'), num1a.LastIndexOf('.')- num1a.IndexOf('.')));

I'm adding a decimal point to the end of the string so that there is at least one decimal point in the number (string). Then grab the text to the left of the first decimal point and concatenate it with any text from the first and to the left of the last decimal point.

If there was no decimal point in the original string then these two points are the same - the substring 0 characters long - removing the added decimal point.

like image 34
K Scandrett Avatar answered Sep 24 '22 16:09

K Scandrett


This is an answer I would be using if this can't be done using one string formatting:

Private Function RoundAndGroup(num As Decimal) As String
    ' This will round the input to limit the number of digit to 16.
    Dim rounded As String = num.ToString("G16")
    ' Take only the whole part of the number to group and then combine with the rounded part.
    Dim whole As String = rounded.Split(".")(0)
    ' Group the whole part (if any) and combine with the rounded part (also if any).
    Dim grouped As String = Long.Parse(whole).ToString("N0") & ' Thanks to KScandrett's comment
                            rounded.Substring(whole.Length)
    Return grouped
End Function

This will -AFAICT- produce my desired output (the same output of Windows calculator).

I just thought that there might be a simple one string formatting to achieve this and I was -and still am- curious to find out if that's true.

like image 34
41686d6564 stands w. Palestine Avatar answered Sep 22 '22 16:09

41686d6564 stands w. Palestine