2014-02-24

When is a Double Not a Double?

I have a class that has a field that is a double. Here is similar code:

public class Test
{
    private double store;

    public double Store
    {
        get
        {
            return this.store;
        }

        set
        {
            if (this.store != value)
            {
                this.store = value;

                // maybe some other stuff such as notifying of property change
            }
        }
    }
}

When you compile this code with Code Contracts Static Contract Checking turned on, it produces a warning that "CodeContracts: Possible precision mismatch for the arguments of ==" on the line with the "if" statement. Why? You are comparing two doubles, which should have the same internal value, you'd think. However, that assumption isn't true, and the warning is legitimate.

In the ECMA C# standard, parameters such as "value" can use whatever internal representation that the hardware wants to use. On Intel x86 architecture this is 80 bits. When you store the value in a double field, it gets truncated to the C# standard double size of 64 bits. So you are comparing an 80 bit floating point number to a 64 bit floating point number. These have different precisions, hence the warning.

You can make the warning go away by casting the parameter (in this case "value") to a double before doing the comparison, like this:

if (this.store != (double)value)

When you think about it, this sort of makes sense. C# wants to use the hardware for floating point processing, because doing math in hardware is much faster than software. However, if you are actually storing the number, it might get persisted somewhere. And if it gets persisted, then it might be read on different hardware that has a different precision, so they want a well-defined storage for doubles.

The C# language specification might have had different data types for the hardware representation and the persisted representation of floating point numbers, however there are relatively few times that this will bite you. When the dragon might rear its head, this warning appears to make you aware of a potential problem. Having two different data types (actually four: float and double and persisted float and double) would make C# more complex for little benefit.

Just be aware that sometimes a double is 64 bits and sometimes it is the hardware length. Make them all 64 bits if you are going to compare them by casting them.

No comments :

Post a Comment