6

How to format a decimal in C# with at least one digit after the decimal point, but not a fixed upper limit if specified more than 1 digit after the decimal point:

5 -> "5.0"
5.1 -> "5.1"
5.122 -> "5.122"
10.235544545 -> "10.235544545"
casperOne
  • 73,706
  • 19
  • 184
  • 253
Stian
  • 223
  • 3
  • 8

3 Answers3

13

Use ToString("0.0###########################").

Some notes:,

  • There are 27 #s in there, as the decimal structure can accommodate precision up to 28 decimal places.
  • The 0 custom specifier will cause a digit to always be displayed, even if the value is 0.
  • The # custom specifier only displays a value if the digit is zero and all of the digits to the right/left of that digit (depending on what side of the decimal point you are on) are zero.
  • You will need to insert as many # after the first 0 to the right of the decimal point to accommodate the length of all the values you will pass to ToString, if you will only have precision to 10 decimal places, then you need nine # (since you have the first decimal place to the right handled by 0)

For more information, see the section of MSDN titled "Custom Numeric Format Strings".

casperOne
  • 73,706
  • 19
  • 184
  • 253
  • Thanks, but looking for a cleaner solution than all the `#`'s – Stian Nov 18 '11 at 14:46
  • @Stian: No way around it, there are no other format specifiers that will do what you want it to do. If you don't use enough `#`, then the result will be rounded. The only other option is to write an extension method `ToString` method which would do what you want. However, you'd have to pass some sort of dummy variable to it, as extension methods will not be called over methods on the type which share the same signature (either that, or call it something else). – casperOne Nov 18 '11 at 14:51
  • @Stian, it's not altogether unclean. But if you wish, and to promote reusability, you can hide that in a static class somewhere and make it an extension method so you don't have to *see* the guts of it, you can just invoke it. @casper, no dummy variable needed, just don't call it `ToString()`. – Anthony Pegram Nov 18 '11 at 14:51
  • @Stian: Updated for all cases, you need one `0` and 27 `#` to cover *all* decimals. @AnthonyPegram: Correct, but I mentioned that in my comment. – casperOne Nov 18 '11 at 14:56
  • 1
    @Stian: Another option would be to create a static `FormatStrings` class with a static or const `AllDecimalDigits` string member with the desired format string. Then you can just do `myDecimal.ToString(FormatStrings.AllDecimalDigits)`. – LukeH Nov 18 '11 at 16:35
2
[TestClass]
public class UnitTest1
{
    [TestMethod]
    public void TestMethod1()
    {
        var a = 5m;
        var b = 5.1m;
        var c = 5.122m;
        var d = 10.235544545m;

        var ar = DecToStr.Work(a);
        var br = DecToStr.Work(b);
        var cr = DecToStr.Work(c);
        var dr = DecToStr.Work(d);

        Assert.AreEqual(ar, "5.0");
        Assert.AreEqual(br, "5.1");
        Assert.AreEqual(cr, "5.122");
        Assert.AreEqual(dr, "10.235544545");
    }
}

public class DecToStr
{
    public static string Work(decimal val)
    {
        if (val * 10 % 10 == 0)
            return val.ToString("0.0");
        else
            return val.ToString();
    }
}
Wojtek Turowicz
  • 4,086
  • 3
  • 27
  • 38
0
Func<decimal, string> FormatDecimal = d => (
    d.ToString().Length <= 3 || 
    !d.ToString().Contains(".")) ? d.ToString("#.0") : d.ToString()
);
casperOne
  • 73,706
  • 19
  • 184
  • 253
Ta01
  • 31,040
  • 13
  • 70
  • 99
  • Won't that fail on something like `d=1000` since the string representation will be longer than 3 characters? – Chris Nov 18 '11 at 14:44
  • oops, fixed that case. still one line. – Ta01 Nov 18 '11 at 14:45
  • I don't like this answer. It is not unreadable. I think Turowicz answer makes the intention of the code clear. – SolutionYogi Nov 18 '11 at 20:16
  • "Its not readable" is very subjective. Its your free will to downvote, but this Func also passes all his unit tests. – Ta01 Nov 18 '11 at 21:00