According to this answer https://stackoverflow.com/a/8315745/5324847 .Net should compare value types by reflection or bitwise. But if we look at this code we can see it's neither (or both of them at once??).
//Bitwise test
//if .Net compares bitwise then last line should be false
//if it uses reflections then last line should be true
float a = -0.0f;
float b = 0.0f;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a))); //prints 000128
Console.WriteLine(string.Join("",BitConverter.GetBytes(b))); //prints 0000
Console.WriteLine(a == b); //True
Console.WriteLine(a.Equals(b)); //prints True
//Reflection test
//if .Net compares using reflection then last line should be false
//if it uses bitwise comparsion then last line should be true
a = float.NaN;
b = float.NaN;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a))); //prints 00192255
Console.WriteLine(string.Join("",BitConverter.GetBytes(b))); //prints 00192255
Console.WriteLine(a == b); //False
Console.WriteLine(a.Equals(b)); //prints True
If we wrap the variable in structure .Net uses bitwise comparsion. Proof:
public struct FloatS
{
public float x;
}
public static void Main()
{
//bitwise test
//if .Net compares bitwise then last line should be false
//if it uses reflections then last line should be true
FloatS a = new FloatS();
FloatS b = new FloatS();
a.x = -0.0f;
b.x = 0.0f;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a.x))); //prints 000128
Console.WriteLine(string.Join("",BitConverter.GetBytes(b.x))); //prints 0000
Console.WriteLine(a.x == b.x); //True
Console.WriteLine(a.Equals(b)); //prints False -- this time corectly because it's bitwise comparsion
//Reflection test
//if .Net compares using reflection then last line should be false
//if it uses bitwise comparsion then last line should be true
a.x = float.NaN;
b.x = float.NaN;
Console.WriteLine(string.Join("",BitConverter.GetBytes(a.x))); //prints 00192255
Console.WriteLine(string.Join("",BitConverter.GetBytes(b.x))); //prints 00192255
Console.WriteLine(a.x == b.x); //False
Console.WriteLine(a.Equals(b)); //prints True - also corectly
}
My asumption was that .Net uses difrent implementation of Equals for primitive types. But that seems incorect because both float and struct type can be cast to System.ValueType .
Can anybody explain what is happening?
According to ... .NET should compare value types by reflection or bitwise.
You're misreading that answer, which is about user-defined value types .
For ==
, floats are compared using special instructions just for floats. Zero and negative zero are equal, NaN equals nothing, not even itself, and so on.
Any type can override Equals
, and System.Single
does so. x.Equals(y)
on floats has the semantics of (x == y) || (IsNaN(x) && IsNaN(y))
(x == y) || (IsNaN(x) && IsNaN(y))
. I do not know for certain why Equals
and ==
were made to have different behaviour, though probably it was to ensure that Equals
on floats is an equivalence relation, which is necessary for certain applications such as putting floats into a hash table. (UPDATE: My supposition is correct; see comment below.)
If you write a user-defined value type and do not provide your own Equals
then you get the default one, which as you note has two big problems:
My assumption was that .NET uses different implementation of Equals for primitive types. But that seems incorrect because both float and struct type can be cast to System.ValueType.
This paragraph makes zero sense to me, and so either I am misunderstanding you, or you believe something completely false about inheritance. Every type can override Equals
. What does that have to do with the fact that user code can box any non-nullable value type? I don't see the connection between your two sentences, and the fact that you believe there is one indicates that someone has a wrong belief here.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.