Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When is a System.Double not a double?

Tags:

c#

clr

After seeing how double.Nan == double.NaN is always false in C#, I became curious how the equality was implemented under the hood. So I used Resharper to decompile the Double struct, and here is what I found:

public struct Double : IComparable, IFormattable, IConvertible, IComparable<double>, IEquatable<double>
{
    // stuff removed...

    public const double NaN = double.NaN;

    // more stuff removed...
}

This seems to indicate the the struct Double declares a constant that is defined in terms of this special lower case double, though I'd always thought that the two were completely synonymous. What's more, if I Go To Implementation on the lowercase double, Resharper simply scrolls me to the declaration at the top of the file. Similarly, jumping to implementation of the lowercase's NaN just takes me to the constant declaration earlier in the line!

So I'm trying to understand this seemingly recursive definition. Is this just an artefact of the decompiler? Perhaps a limitation in Resharper? Or is this lowercase double actually a different beast altogether - representing something at a lower level from the CLR/CTS?

Where does NaN really come from?

like image 504
Mike Chamberlain Avatar asked May 22 '13 13:05

Mike Chamberlain


People also ask

What is System double?

The Double value type represents a double-precision 64-bit number with values ranging from negative 1.79769313486232e308 to positive 1.79769313486232e308, as well as positive or negative zero, Double. PositiveInfinity, Double. NegativeInfinity, and Not-a-Number ( Double. NaN).

What is the difference between double and double in C#?

There is no difference. double is just an alias for System. Double in C#.

How do you check if a number is a double in C#?

You can use double. TryParse() it will return false if it couldn't create a double.

What is double [] in C#?

The double is a fundamental data type built into the compiler and used to define numeric variables holding numbers with decimal points. C, C++, C# and many other programming languages recognize the double as a type. A double type can represent fractional as well as whole values.


2 Answers

Beware looking at decompiled code, especially if it is for something inbuilt. The actual IL here (for .NET 4.5, at least) is:

.field public static literal float64 NaN = float64(NaN)
{
    .custom instance void __DynamicallyInvokableAttribute::.ctor()
}

i.e. this is handled directly in IL via the NaN token.

However, because it is a const (literal in IL), it will get "burned into" the call site; anywhere else that uses double.NaN will also be using float64(NaN). Similarly, example, if I do:

const int I = 2;
int i = I;
int j = 2;

both of these assignments will look identical in the final IL (they will both be ldc.i4.2).

Because of this, most decompilers will recognise the IL pattern NaN and represent it with the language's equivalent of double.NaN. But that doesn't mean that the code is itself recursive; they probably just don't have a check for "but is it double.NaN itself?". Ultimately, this is simply a special case, where float64(NaN) is a recognised value in IL.

Incidentally, reflector decompiles it as:

[__DynamicallyInvokable]
public const double NaN = (double) 1.0 / (double) 0.0;

That again doesn't meant that this is truth :p Merely that this is something which may have the same end result.

like image 196
Marc Gravell Avatar answered Sep 18 '22 22:09

Marc Gravell


By far the best source you can get for .NET assemblies is the actual source code that was used to build them. Beats any decompiler for accuracy, the comments can be quite useful as well. Download the Reference Source.

You'll then also see that Double.NaN isn't defined in IL as Marc assumed, it's actually in a C# source code file. The net/clr/bcl/system/double.cs source code file shows the real declaration:

  public const double NaN = (double)0.0 / (double)0.0;

Which takes advantage of the C# compiler evaluating constant expressions at compile time. Or to put it tongue-in-cheek, NaN is defined by the C++ compiler since that's the language that was used to write the C# compiler ;)

like image 29
Hans Passant Avatar answered Sep 18 '22 22:09

Hans Passant