0

I wrote a code that runs inconsistently on 3 different machines. Now I'm trying to track the reason of inconsistency and I found the following:
This code generates randomly erroneous results on my computer (didn't try on another yet):

using System;
using System.Collections.Generic;

namespace justfortest
{
    class param : IComparable<param> 
    {
        public int par1;
        public int par2;
        public int par3;
        public int par4;
        public int par5;
        public int par6;
        public int par7;
        public double par8;
        public double par9;
        public double par10;
        public double par11;

        int IComparable<param>.CompareTo(param other)
        {
            throw new NotImplementedException();
        }
    }
    class Program
    {
        static void Main(string[] args)
        {
            List<param> paramList = new List<param>(10000000);

            for (int par1 = 8; par1 <= 20; par1 += 4)
            {
                for (int par2 = 10; par2 <= 25; par2 += 5)
                {
                    for (int par3 = 6; par3 <= 18; par3 += 4)
                    {
                        for (int par4 = 14; par4 <= 20; par4 += 3)
                        {
                            for (int par5 = 10; par5 <= 20; par5 += 5)
                            {
                                for (int par6 = 4; par6 <= 10; par6 += 2)
                                {
                                    for (int par7 = 5; par7 <= 30; par7 += 5)
                                    {
                                        for (double par8 = 1.0005; par8 <= 1.002; par8 += 0.0005)
                                        {
                                            for (double par9 = 1.002; par9 <= 1.0048; par9 += 0.0007)
                                            {
                                                for (double par10 = 0.2; par10 <= 0.5; par10 += 0.1)
                                                {
                                                    for (double par11 = 0.5; par11 <= 2; par11 += 0.5)
                                                    {
                                                        param p = new param();
                                                        p.par1 = par1;
                                                        p.par2 = par2;
                                                        p.par3 = par3;
                                                        p.par4 = par4;
                                                        p.par5 = par5;
                                                        p.par6 = par6;
                                                        p.par7 = par7;
                                                        p.par8 = par8;
                                                        p.par9 = par9;
                                                        p.par10 = par10;
                                                        p.par11 = par11;
                                                        paramList.Add(p);
                                                    }
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            Console.WriteLine();  //to place a break here and observe the results
        }
    }
}

The problem is about par8 to par11 that are defined as double. Their value is not always what is expected. For example sometimes par10 becomes 0.30000000000000004 instead of 0.3. After this par10==0.3 evaluates as false in the code later. The above sample reproduces the error for me.
I use .NET 4.5.2 and I tried the same in 4.6.1.
It seems that this behaviour appears randomly, at least I could not find a pattern. The only thing I noticed that with time it gets worse. In the beginning maybe only 1 of the doubles is like this in a param, but 100.000 items later all of them.
I really don't know what to do about this. Any clues?

Manngo
  • 829
  • 7
  • 24
  • 3
    If you need absolute accuracy from a decimal number standpoint then use `decimal` instead of `double` That said, I would expect the behavior to be _consistent_ even if it's not what you _expect_. – D Stanley May 03 '16 at 21:18
  • I checked. par10==0.3 returns false when par10 is 0.30000000000000004. – Manngo May 03 '16 at 21:20
  • The precision of a 64 bit floating point number is only 15 - 16 digits. The error in your example occurs beyond that range. In all likelihood that will affect all languages using 64 bit floating point numbers. If you need precision beyond that you will have to switch to decimal as was mentioned (that is represented as binary coded decimal). – Oliver Ulm May 03 '16 at 21:20
  • I don't see how your code could throw an exception at all - you never compare one `param` to another, so `CompareTo` should never be called. What kind or exception do you get? – D Stanley May 03 '16 at 21:21
  • 1
    Results will vary depending if you compile as Debug or Release. Debug should give the same results since it is done in software. Release uses the Microprocessor floating point unit (FPU). Some FPUs have design flaws. What makes the issue worse is Microsoft have developed some software patches that attempts to compensate for the FPU flaws. But the patches also have flaws and some times executes the patch on FPUs that don't have flaws which give incorrect results. – jdweng May 03 '16 at 21:21
  • 1
    @Manngo 0.3 can't be represented _exactly_ as a binary floating-point number. Don't use double if you need a value to equal to 0.3 _excatly_. – D Stanley May 03 '16 at 21:23
  • I agree with D Stanley: use decimal. Instead of "double par8 = 1.0005" write "decimal par8 = 1.0005m". "m" suffix is important - otherwise 1.0005 wil be compiled as double and you will recive not accurate result. More in MSDN: https://msdn.microsoft.com/en-us/library/364x0z75.aspx – Artyom May 03 '16 at 21:35
  • @Artyom Actually it will be a compiler error since you can't implicitly convert from `double` to `decimal`, but your point is valid. – D Stanley May 03 '16 at 21:44
  • Thanks a lot to all! And sorry for the silly question... – Manngo May 03 '16 at 22:04

0 Answers0