JC.
JC.

Reputation: 11801

Best way to display decimal without trailing zeroes

Is there a display formatter that will output decimals as these string representations in c# without doing any rounding?

// decimal -> string

20 -> 20
20.00 -> 20
20.5 -> 20.5
20.5000 -> 20.5
20.125 -> 20.125
20.12500 -> 20.125
0.000 -> 0

{0.#} will round, and using some Trim type function will not work with a bound numeric column in a grid.

Upvotes: 137

Views: 130899

Answers (14)

Michel van Engelen
Michel van Engelen

Reputation: 2879

Given the fact that the OP stated examples with at most 5 digits, would this work for all input?

var result = (decimal)((double) input).ToString(); //with input e.g. 20.12500M

I know that the precision of double and decimal is not the same and this can lead to rounding when performing calculations, but maybe for this given question it is watertight.

Upvotes: 0

Tim
Tim

Reputation: 5839

You can use the G0 format string if you are happy to accept scientific notation as per the documentation:

Fixed-point notation is used if the exponent that would result from expressing the number in scientific notation is greater than -5 and less than the precision specifier; otherwise, scientific notation is used.

You can use this format string as a parameter to the .ToString() method, or by specifying it as a within an interpolated string. Both are shown below.

decimal hasTrailingZeros = 20.12500m;
Console.WriteLine(hasTrailingZeros.ToString("G0")); // outputs 20.125
Console.WriteLine($"{hasTrailingZeros:G0}"); // outputs 20.125

decimal fourDecimalPlaces = 0.0001m;
Console.WriteLine(fourDecimalPlaces.ToString("G0")); // outputs 0.0001
Console.WriteLine($"{fourDecimalPlaces:G0}"); // outputs 0.0001

decimal fiveDecimalPlaces = 0.00001m;
Console.WriteLine(fiveDecimalPlaces.ToString("G0")); // outputs 1E-05
Console.WriteLine($"{fiveDecimalPlaces:G0}"); // outputs 1E-05

Upvotes: 3

KevinBui
KevinBui

Reputation: 1099

You can create extension method

public static class ExtensionMethod {
  public static decimal simplify_decimal(this decimal value) => decimal.Parse($"{this:0.############}");
}

Upvotes: 1

lilo0
lilo0

Reputation: 1025

I have end up with this variant:

public static string Decimal2StringCompact(decimal value, int maxDigits)
    {
        if (maxDigits < 0) maxDigits = 0;
        else if (maxDigits > 28) maxDigits = 28;
        return Math.Round(value, maxDigits, MidpointRounding.ToEven).ToString("0.############################", CultureInfo.InvariantCulture);
    }

Advantages:

you can specify the max number of significant digits after the point to display at runtime;

you can explicitly specify a round method;

you can explicitly control a culture.

Upvotes: 0

Mervin
Mervin

Reputation: 1103

It's quite easy to do out of the box:

Decimal YourValue; //just as example   
String YourString = YourValue.ToString().TrimEnd('0','.');

that will remove all trailing zeros from your Decimal.

The only thing that you need to do is add .ToString().TrimEnd('0','.'); to a decimal variable to convert a Decimal into a String without trailing zeros, like in the example above.

In some regions it should be a .ToString().TrimEnd('0',','); (where they use a comma instead of a point, but you can also add a dot and a comma as parameters to be sure).

(you can also add both as parameters)

Upvotes: 2

Arsen Zahray
Arsen Zahray

Reputation: 25287

I ended up with the following code:

    public static string DropTrailingZeros(string test)
    {
        if (test.Contains(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.TrimEnd('0');
        }

        if (test.EndsWith(CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator))
        {
            test = test.Substring(0,
                test.Length - CultureInfo.InvariantCulture.NumberFormat.NumberDecimalSeparator.Length);
        }

        return test;
    }

Upvotes: 0

David Dostal
David Dostal

Reputation: 751

Another solution, based on dyslexicanaboko's answer, but independent of the current culture:

public static string ToTrimmedString(this decimal num)
{
    string str = num.ToString();
    string decimalSeparator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
    if (str.Contains(decimalSeparator))
    {
        str = str.TrimEnd('0');
        if(str.EndsWith(decimalSeparator))
        {
            str = str.RemoveFromEnd(1);
        }
    }
    return str;
}

public static string RemoveFromEnd(this string str, int characterCount)
{
    return str.Remove(str.Length - characterCount, characterCount);
}

Upvotes: 6

OKEEngine
OKEEngine

Reputation: 908

decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');

Upvotes: 1

dyslexicanaboko
dyslexicanaboko

Reputation: 4275

This is yet another variation of what I saw above. In my case I need to preserve all significant digits to the right of the decimal point, meaning drop all zeros after the most significant digit. Just thought it would be nice to share. I cannot vouch for the efficiency of this though, but when try to achieve aesthetics, you are already pretty much damned to inefficiencies.

public static string ToTrimmedString(this decimal target)
{
    string strValue = target.ToString(); //Get the stock string

    //If there is a decimal point present
    if (strValue.Contains("."))
    {
        //Remove all trailing zeros
        strValue = strValue.TrimEnd('0');

        //If all we are left with is a decimal point
        if (strValue.EndsWith(".")) //then remove it
            strValue = strValue.TrimEnd('.');
    }

    return strValue;
}

That's all, just wanted to throw in my two cents.

Upvotes: 12

Schmalls
Schmalls

Reputation: 1474

I just learned how to properly use the G format specifier. See the MSDN Documentation. There is a note a little way down that states that trailing zeros will be preserved for decimal types when no precision is specified. Why they would do this I do not know, but specifying the maximum number of digits for our precision should fix that problem. So for formatting decimals, G29 is the best bet.

decimal test = 20.5000m;
test.ToString("G"); // outputs 20.5000 like the documentation says it should
test.ToString("G29"); // outputs 20.5 which is exactly what we want

Upvotes: 47

Erwin Mayer
Erwin Mayer

Reputation: 18670

This string format should make your day: "0.#############################". Keep in mind that decimals can have at most 29 significant digits though.

Examples:

? (1000000.00000000000050000000000m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.00000000000050000000001m).ToString("0.#############################")
-> 1000000.0000000000005

? (1000000.0000000000005000000001m).ToString("0.#############################")
-> 1000000.0000000000005000000001

? (9223372036854775807.0000000001m).ToString("0.#############################")
-> 9223372036854775807

? (9223372036854775807.000000001m).ToString("0.#############################")
-> 9223372036854775807.000000001

Upvotes: 20

Toby
Toby

Reputation: 7544

Do you have a maximum number of decimal places you'll ever need to display? (Your examples have a max of 5).

If so, I would think that formatting with "0.#####" would do what you want.

    static void Main(string[] args)
    {
        var dList = new decimal[] { 20, 20.00m, 20.5m, 20.5000m, 20.125m, 20.12500m, 0.000m };

        foreach (var d in dList)
            Console.WriteLine(d.ToString("0.#####"));
    }

Upvotes: 179

Tim Skauge
Tim Skauge

Reputation: 1844

I don't think it's possible out-of-the-box but a simple method like this should do it

public static string TrimDecimal(decimal value)
{
    string result = value.ToString(System.Globalization.CultureInfo.InvariantCulture);
    if (result.IndexOf('.') == -1)
        return result;

    return result.TrimEnd('0', '.');
}

Upvotes: 2

jgauffin
jgauffin

Reputation: 101140

Extension method:

public static class Extensions
{
    public static string TrimDouble(this string temp)
    {
        var value = temp.IndexOf('.') == -1 ? temp : temp.TrimEnd('.', '0');
        return value == string.Empty ? "0" : value;
    }
}

Example code:

double[] dvalues = {20, 20.00, 20.5, 20.5000, 20.125, 20.125000, 0.000};
foreach (var value in dvalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.ToString().TrimDouble()));

Console.WriteLine("==================");

string[] svalues = {"20", "20.00", "20.5", "20.5000", "20.125", "20.125000", "0.000"};
foreach (var value in svalues)
    Console.WriteLine(string.Format("{0} --> {1}", value, value.TrimDouble()));

Output:

20 --> 20
20 --> 20
20,5 --> 20,5
20,5 --> 20,5
20,125 --> 20,125
20,125 --> 20,125
0 --> 0
==================
20 --> 20
20.00 --> 2
20.5 --> 20.5
20.5000 --> 20.5
20.125 --> 20.125
20.125000 --> 20.125
0.000 --> 0

Upvotes: 2

Related Questions