1

How to count precision digits on a C# decimal type?

e.g. 12.001 = 3 precision digits.

I would like to thrown an error is a precision of greater than x is present.

Thanks.

MammothOne
  • 490
  • 2
  • 5
  • 12
  • So if you divide this by 2 to get 6.0005 then an exception should be thrown? Good luck writing the math library to go along with that. – Hans Passant Aug 28 '13 at 16:34

4 Answers4

3
public int CountDecPoint(decimal d){
   string[] s = d.ToString().Split('.');
   return s.Length == 1 ? 0 : s[1].Length;
}

Normally the decimal separator is ., but to deal with different culture, this code will be better:

public int CountDecPoint(decimal d){
   string[] s = d.ToString().Split(Application.CurrentCulture.NumberFormat.NumberDecimalSeparator[0]);
   return s.Length == 1 ? 0 : s[1].Length;
}
King King
  • 61,710
  • 16
  • 105
  • 130
2

You can get the "scale" of a decimal like this:

static byte GetScale(decimal d)
{
  return BitConverter.GetBytes(decimal.GetBits(d)[3])[2];
}

Explanation: decimal.GetBits returns an array of four int values of which we take only the last one. As described on the linked page, we need only the second to last byte from the four bytes that make up this int, and we do that with BitConverter.GetBytes.

Examples: The scale of the number 3.14m is 2. The scale of 3.14000m is 5. The scale of 123456m is 0. The scale of 123456.0m is 1.


If the code may run on a big-endian system, it is likely that you have to modify to BitConverter.GetBytes(decimal.GetBits(d)[3])[BitConverter.IsLittleEndian ? 2 : 1] or something similar. I have not tested that. See the comments by relatively_random below.

Jeppe Stig Nielsen
  • 60,409
  • 11
  • 110
  • 181
  • Would this still work on a system with different endianness? – relatively_random Oct 21 '16 at 12:46
  • @relatively_random Not sure. Are there implementations of .NET running on big-endian systems? I think we would have to consult the documentations of `decimal.GetBits` and `BitConverter.GetBytes` from those implementation of .NET to find out if their outputs depend on the endianness. I see Microsoft .NET has a field `BitConverter.IsLittleEndian`, I do not know if they built their framework for big-endian architecture. Related: [Details about Endian-ness and .Net?](http://stackoverflow.com/questions/3162986/) – Jeppe Stig Nielsen Oct 21 '16 at 15:22
  • 1
    According to your link, there are big-endian .NET implementations. BitConverter is sensitive to endianness, according to [MSDN](https://msdn.microsoft.com/en-us/library/system.bitconverter.aspx). And I would interpret what is written about [Decimal.GetBits](https://msdn.microsoft.com/en-us/library/system.decimal.getbits.aspx) that it produces the same output regardless of the machine. So the method should probably be modified to check for BitConverter.IsLittleEndian and to get byte index 1 if false. – relatively_random Oct 22 '16 at 12:20
0

I know I'm resurrecting an ancient question, but here's a version that doesn't rely on string representations and actually ignores trailing zeros. If that's even desired, of course.

public static int GetMinPrecision(this decimal input)
{
    if (input < 0)
        input = -input;

    int count = 0;
    input -= decimal.Truncate(input);
    while (input != 0)
    {
        ++count;
        input *= 10;
        input -= decimal.Truncate(input);
    }

    return count;
}
relatively_random
  • 4,505
  • 1
  • 26
  • 48
0

I would like to thrown an error is a precision of greater than x is present

This looks like the simplest way:

void AssertPrecision(decimal number, int decimals)
{
    if (number != decimal.Round(number, decimals, MidpointRounding.AwayFromZero))
        throw new Exception()
};
Piotr Nawrot
  • 420
  • 6
  • 13