-1

I want to calculate the number of digits after the decimal point of a decimal number. My program works, but it returns the wrong number when I add more digits, for example, 5.55266666666555555 has 17 digits after the decimal point, but my program returns only 15.

using System;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Result is: {0}", howMuchDots(5.55266666666555555));
    }

    static double howMuchDots(double num)
    {
        /* Convert num to string, split it with dot into an array, and take the second cell. Then get the length of the string */
        return num.ToString().Split(".")[1].Length;
    }
}

I tried to use float instead, but it doesn't work either.

marc_s
  • 732,580
  • 175
  • 1,330
  • 1,459
  • Double only has about 15-17 digits precision: https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/floating-point-numeric-types – SomeBody Jan 14 '21 at 09:10
  • @SomeBody Yeah that is what I thought, then, why should I do? – zer0-padding Jan 14 '21 at 09:11
  • 1
    Note that formatting the double into a string will often do some simplification. Use the "G17" format to see all of the gory details. That won't help if you're pushingthe limits of double precision however – canton7 Jan 14 '21 at 09:11
  • 1
    Since you're dealing with numbers accurate to many significant figures, and you need to accurately represent numbers in base 10 (without the changes that converting to base 2 adds), it would probably be better to use `decimal` rather than `double`: https://dotnetfiddle.net/GgMPe7 – canton7 Jan 14 '21 at 09:12
  • 2
    Probably not relevant in this context, but consider also that a ToString on a floating point number inserts the decimal separator for the current culture and not all cultures uses the . to separate the decimal part. On my machine, for example, your code fails at the split call. Because there is no point but a comma to split on – Steve Jan 14 '21 at 09:14
  • @canton7 Why should I use `decimal`? It is an Integer, no? It gives me an error when I give a decimal number as an argument to the function. – zer0-padding Jan 14 '21 at 09:22
  • @zer0-padding `decimal` is not an integer, no. See the link in my last comment, when I demonstrate it being used – canton7 Jan 14 '21 at 09:25
  • Fun fact, how c# will display a floating point value (no matter how your format it) and what it actually is are sometimes 2 different things. In that respect this question becomes nearly futile – TheGeneral Jan 14 '21 at 09:50
  • What is the expected result if the `decimal` is 1.0000000m? – mjwills Jan 14 '21 at 10:28
  • @mjwills Probably the amount of zeros in the decimal literal, I guess. – zer0-padding Mar 02 '21 at 15:40

2 Answers2

3

In general, the difference between the float, double and decimal data types lies in the precision and therefore also in how much memory is used to hold them. The float is the least expensive one - it can represent a number with up to 7 digits. The double is more precise, with up to 16 digits, while the decimal is the most precise, with a whooping maximum of 29 digits.

You just need to change the type of your argument to decimal.

using System;

class Program
{
    static void Main(string[] args)
    {
        Console.WriteLine("Result is: {0}", howMuchDots(5.55266666666555555m));
    }

    static int howMuchDots(decimal num)
    {
        var length = (num - Math.Truncate(num)).ToString().Length - 2;
        return length > 0 ? length : 0;
    }
}
Sajjad Mortazavi
  • 190
  • 2
  • 12
  • Note that the limits of precision for float and double aren't hard limits -- you get between around 6 to 9 digits of precision for a float for example, depending on the exact number you're trying to represent. – canton7 Jan 14 '21 at 09:16
  • 2
    While true statement how it relates to the question - "how much decimal numbers there is after a dot"... I.e. some good words could be written for 1.234567e10 - does it have 6 number after dot or zero... – Alexei Levenkov Jan 14 '21 at 09:16
  • Hey, it doesn't work for me. `Cannot convert from double to decimal`. – zer0-padding Jan 14 '21 at 09:20
  • @zer0-padding: Call it with `howMuchDots(5.55266666666555555m)` – SomeBody Jan 14 '21 at 09:33
  • @SomeBody What does the `m` represent? – zer0-padding Jan 14 '21 at 09:37
  • @zer0-padding How about casting to string and dealing with strings inside your method? – Sajjad Mortazavi Jan 14 '21 at 09:37
  • 1
    @zer0-padding https://stackoverflow.com/questions/977484/what-does-the-m-stand-for-in-c-sharp-decimal-literal-notation – canton7 Jan 14 '21 at 09:37
  • 1
    This answer has some problems. First it assumes that the dot is the separator and this is not always the case, then it doesn't deal with numbers that doesn't have decimals. Third, Split with just a single string parameter doesn't work on NET Framework (works in core or net5) – Steve Jan 14 '21 at 09:51
  • Yes, this answer is flawed in several ways. – TheGeneral Jan 14 '21 at 09:57
  • @mjwills It is accurate up to 28 decimal numbers – Sajjad Mortazavi Jan 14 '21 at 10:45
  • Let's hope that number isn't negative. ;) – mjwills Jan 14 '21 at 11:14
  • And what about 1.00000000000000001? Calling ToString on certain double inevitably rounds and truncates some part or the number. Even with the sample number provided by the asker you should get as result 17 but this code returns 15. – Steve Jan 14 '21 at 13:31
  • 1
    If you try your example, the result would be 17. `num` is not a double but a decimal – Sajjad Mortazavi Jan 14 '21 at 13:58
  • I see, tried with double as OP posted initially – Steve Jan 14 '21 at 14:12
3

You say you want to use a decimal but your method takes a double.

Assuming you actually want to use a decimal this works. Try using GetBits method to convert several Decimal values to their equivalent binary representations.

using System;

namespace ConsoleApp7
{
    class Program
    {
        static void Main(string[] args)
        {
            decimal[] decimalValues = { 1M, 100000000000000M, 10000000000000000000000000000M,
                100000000000000.00000000000000M, 1.0000000000000000000000000000M,
                123456789M, 0.123456789M, 0.000000000123456789M,
                0.000000000000000000123456789M, 4294967295M,
                18446744073709551615M, decimal.MaxValue,
                decimal.MinValue, -7.9228162514264337593543950335M, 5.55266666666555555M };

            foreach (var num in decimalValues)
            {
                Console.WriteLine($"{num} Result is: {howMuchDots(num)}");
            }
            Console.ReadLine();
        }
        static double howMuchDots(decimal num)
        {
            return  (decimal.GetBits(num)[3] >> 16) & 0x000000FF;
        }
    }
}
Linda Lawton - DaImTo
  • 106,405
  • 32
  • 180
  • 449