Reputation: 11801
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
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
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
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
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
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
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
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
Reputation: 908
decimal val = 0.000000000100m;
string result = val == 0 ? "0" : val.ToString().TrimEnd('0').TrimEnd('.');
Upvotes: 1
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
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
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
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
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
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