Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Double datatype, count decimals after decimal-place

Tags:

c#

Method below should return a answer to "What decimal precision, quantity of trailing numbers, do this (double) value have?". I got it right when the values looks like 5900.43, 5900.043 and so on. When the method recieves 5900.00, it return 0, which is wrong (in my need).

   /// <summary>
   /// Return count of decimals after decimal-place 
   /// </summary>
   private int getDecimalCount(double val)
   {
        int count = 0;
        ...
        return count;
   }

When parameter 'val' is (samples of normal values to this method)

5900.00 return 2
5900.09 return 2
5900.000 return 3
5900.001 return 3
1.0 return 1
0.0000005 return 7
1.0000000 return 7
5900822 return 0

My problem is counting .0 .00 .000 and so on

Question:
How do I solve this? If this method isn't possible with doubles, how else?

[EDITED]
- Minor text change to make a more clear question,
- Language correction due to miss-used meaning of 'decimal places'

like image 697
Independent Avatar asked Sep 08 '11 10:09

Independent


People also ask

How many decimal places does a double data type have?

double has 15 decimal digits of precision.

Can double have decimal values?

How many joule in 1 decimal? The answer is 1. Note that rounding errors may occur, so always check the results.

How many decimal places of accuracy does a double have?

Double precision numbers are accurate up to sixteen decimal places but after calculations have been done there may be some rounding errors to account for.


1 Answers

EDIT: Updated to simplify handling different cultures.

Similarly to @Miguel, here's how I would handle it:

public static int getDecimalCount(double dVal, string sVal, string culture)
{
    CultureInfo info = CultureInfo.GetCultureInfo(culture);

    //Get the double value of the string representation, keeping culture in mind
    double test = Convert.ToDouble(sVal, info);

    //Get the decimal separator the specified culture
    char[] sep = info.NumberFormat.NumberDecimalSeparator.ToCharArray();

    //Check to see if the culture-adjusted string is equal to the double
    if (dVal != test)
    {
        //The string conversion isn't correct, so throw an exception
        throw new System.ArgumentException("dVal doesn't equal sVal for the specified culture");
    }

    //Split the string on the separator 
    string[] segments = sVal.Split(sep);

    switch (segments.Length)
    {
        //Only one segment, so there was not fractional value - return 0
        case 1:
            return 0;
        //Two segments, so return the length of the second segment
        case 2:
            return segments[1].Length;

        //More than two segments means it's invalid, so throw an exception
        default:
            throw new Exception("Something bad happened!");
    }
}

And a shortcut method for US English:

public static int getDecimalCount(double dVal, string sVal)
{
    return getDecimalCount(dVal, sVal, "en-US");
}

Testing:

static void Main(string[] args)
{
    int i = 0;

    double d = 5900.00; 
    string s = "5900.00";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 2. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.09;
    s = "5900.09";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 2. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.000;
    s = "5900.000";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 3. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900.001;
    s = "5900.001";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 3. Actual output: {0}", i);
    Console.WriteLine();

    d = 1.0; 
    s = "1.0";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 1. Actual output: {0}", i);
    Console.WriteLine();

    d = 0.0000005; 
    s = "0.0000005";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 7. Actual output: {0}", i);
    Console.WriteLine();

    d = 1.0000000; 
    s = "1.0000000";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 7. Actual output: {0}", i);
    Console.WriteLine();

    d = 5900822; 
    s = "5900822";
    Console.WriteLine("Testing with dVal = {0} and sVal = {1}.", d, s);
    i = getDecimalCount(d, s);
    Console.WriteLine("Expected output: 0. Actual output: {0}", i);

    Console.ReadLine();
}

And finally, the output of the test:

Testing with dVal = 5900 and sVal = 5900.00. Expected output: 2. Actual output: 2

Testing with dVal = 5900.09 and sVal = 5900.09. Expected output: 2. Actual output: 2

Testing with dVal = 5900 and sVal = 5900.000. Expected output: 3. Actual output: 3

Testing with dVal = 5900.001 and sVal = 5900.001. Expected output: 3. Actual output: 3

Testing with dVal = 1 and sVal = 1.0. Expected output: 1. Actual output: 1

Testing with dVal = 5E-07 and sVal = 0.0000005. Expected output: 7. Actual output: 7

Testing with dVal = 1 and sVal = 1.0000000. Expected output: 7. Actual output: 7

Testing with dVal = 5900822 and sVal = 5900822. Expected output: 0. Actual output: 0

Let me know if you have questions about it or it doesn't make sense.

like image 175
Rick Liddle Avatar answered Nov 15 '22 12:11

Rick Liddle