Best way to display decimal without trailing zeroes
C#FormattingDecimalC# Problem Overview
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.
C# Solutions
Solution 1 - C#
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.#####"));
}
Solution 2 - C#
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
Solution 3 - C#
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
Solution 4 - C#
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.
Solution 5 - C#
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);
}
Solution 6 - C#
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
Solution 7 - C#
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', '.');
}
Solution 8 - C#
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)
Solution 9 - C#
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
Solution 10 - C#
decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');
Solution 11 - C#
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;
}
Solution 12 - C#
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.
Solution 13 - C#
You can create extension method
public static class ExtensionMethod {
public static decimal simplify_decimal(this decimal value) => decimal.Parse($"{this:0.############}");
}