1

I'm trying to learn C# and I was interested in trying to write a simple do-while to calculate a square root of a simple number

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;



namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {


            double x = Convert.ToDouble(Console.ReadLine());
            double root = 0;
            do
            {
                root += 0.0001;
                Console.WriteLine(root);
            }
            while ((root * root) % x != 0);


            Console.WriteLine(Math.Sqrt(x));
            Console.WriteLine(root);


        }
    }
}

If I use a round number for root += 0.0001; like root +=1; it works perfectly for even answers but once I start using 0.1 or smaller it breaks, and even ignores it's check in the while statement.

Can anybody explain why this happens? NOTE: I don't need a solution just the reason why this happens. And I know I can use Math.Sqrt(value);

  • 1
    Don't use double, float for comparison of floating point numbers ! http://csharpindepth.com/Articles/General/FloatingPoint.aspx – mybirthname Nov 10 '16 at 01:37
  • 1
    `while ((root * root) - x < epsilon);` where `epsilon` is a sufficiently small number is probably a better comparison – D Stanley Nov 10 '16 at 01:53

1 Answers1

1

Credits to @JonSkeet for his answer here (and @PaulHicks for mentioning it)

float and double are floating binary point types. In other words, they represent a number like this:

10001.10010110011

The binary number and the location of the binary point are both encoded within the value.

decimal is a floating decimal point type. In other words, they represent a number like this:

12345.65789

Doing it like this, hence, fixes the problem:

int x = 4;
decimal root = 0;
do
{
    root += 0.0001M;
}
while ((root * root) % x != 0);
Trace.WriteLine(Math.Sqrt(x));
Trace.WriteLine(root);
Community
  • 1
  • 1
Camilo Terevinto
  • 31,141
  • 6
  • 88
  • 120
  • How can it be a precision error if it even breaks at 0.1? and it also skips the correct answer although it's being printed – Jesha Kuizenga Nov 10 '16 at 01:36
  • You might want to read more here: http://stackoverflow.com/q/618535/3195526 – Paul Hicks Nov 10 '16 at 01:37
  • @PaulHicks Thanks for that link – Camilo Terevinto Nov 10 '16 at 01:40
  • 1
    No, this is bad. `decimal` is just another floating-point representation. It suffers the same issue that `double` does but just less often. Using `!=` or `==` on `decimal` can have exactly the same problems as `double`. – Enigmativity Nov 10 '16 at 01:44
  • Yw :) I guess it was mostly for OP. In particular the bit "not all decimal numbers are exactly representable in binary floating point – 0.1, for example" – Paul Hicks Nov 10 '16 at 01:44
  • No @Enigmativity it isn't bad in this case. It's not a binary floating point number, and 0.1 is _correctly and exactly_ represented as a decimal. It is not exactly represented as a float or double. It would be as bad if decimal was being used to represent (1/3). – Paul Hicks Nov 10 '16 at 01:45
  • 2
    @PaulHicks - Yes, correct. There are numbers like `1/3` that are bad. That's my point. For this solution to be valid those issues need to be stated. – Enigmativity Nov 10 '16 at 01:50
  • 2
    thanks, so simply said: The comparison breaks because of the binary numbers being compared, and not the true values(displayed values), which leads to no match, because the binary numbers don't match? – Jesha Kuizenga Nov 10 '16 at 02:04