19

I noticed that .NET has some funky/unintuitive behavior when it comes to decimals and trailing zeros.

0m == 0.000m //true
0.1m == 0.1000m //true

but

(0m).ToString() == (0.000m).ToString() //false
(0.1m).ToString() == (0.1000m).ToString() //false

I know about necessity to comply to the ECMA CLI standard. However I would like to know if there is built-in way to truncate the trailing zeros for a decimal value without going through string representation (.ToString("G29") and parse back trick would work, but is neither fast nor elegant solution)?

Any ideas? Thanks a lot.

Konrad
  • 558
  • 1
  • 5
  • 16
  • Hmmm... I'm thinking something involving `decimal.GetBits` and 96-bit arithmetic, but not simple. – Marc Gravell Apr 26 '10 at 15:34
  • 1
    See http://stackoverflow.com/questions/1584314/ for a related question. One of the answers there gives the trick of dividing by 1.000....0000m to effectively remove trailing zeros (presumably because the 'ideal' exponent for a quotient x/y is the difference of the exponents of x and y). It's surprising that there's no `normalize` method, though. – Mark Dickinson Apr 26 '10 at 15:42

3 Answers3

20

I think that what you need is this (more details in my answer here) :

public static decimal Normalize(decimal value)
{
    return value/1.000000000000000000000000000000000m;
}
Community
  • 1
  • 1
Thomas Materna
  • 3,619
  • 1
  • 17
  • 14
  • 1
    This is the fastest I've come across and beats my own attempts at binary twiddling, although they easily beat all the other contenders here, including [this somewhat similar approach](http://stackoverflow.com/a/20647024/709537) on a [duplicate question](http://stackoverflow.com/q/4525854/709537). – Evgeniy Berezovsky Apr 08 '15 at 03:07
7

Use a format string to specify the output of ToString():

(0.1m).ToString("0.#") -> "0.1"
(0.10000m).ToString("0.#") -> "0.1"

Use a "0" in the format to specify a digit or a non-significate 0, use "#" to specify a significant digit or suppress a a non-significate 0.

Edit: I assuming here that you are worried about the visual (string) representation of the number - if not, I will remove my answer.

Ray
  • 21,485
  • 5
  • 48
  • 64
  • 1
    I don't care that much about visual representation. The problem is that when I pass those values to the JScript engine, it gets messed up for some reason by the 1.0000m type values. Thx for the answer any nonetheless. P.S. 0.10000m.ToString("G29") works for any number of significant digits. – Konrad Apr 26 '10 at 19:31
  • 1
    This will also round the value, for example 123.4567 with 0.# applied becomes 123.5 – CRice Jan 13 '11 at 00:42
3

I don't like it much, but it works (for some range of values, at least)...

    static decimal Normalize(decimal value)
    {
        long div = 1;
        while(value - decimal.Truncate(value) != 0)
        {
            div *= 10;
            value *= 10;
        }
        if(div != 1) {
            value = (decimal)(long)value / div;
        }
        return value;
    }
Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • It works for most cases. Unfortunately it doesn't work for 0.00000m type of values. It would need another 'if' to check for decimal zero and this would make it even more messy. – Konrad Apr 26 '10 at 19:55