code(from interactive shell):
> var a = new Dictionary<float, string>();
> a.Add(float.NaN, "it is NaN");
> a[float.NaN]
"it is NaN"
So it is possible, but is it safe?
code(from interactive shell):
> var a = new Dictionary<float, string>();
> a.Add(float.NaN, "it is NaN");
> a[float.NaN]
"it is NaN"
So it is possible, but is it safe?
That depends on what you mean by safe.
If you expect people to be able to use the dictionary and compare its keys to other floats, they will have to deal with a key value of NaN
correctly themselves. And since float.NaN == float.NaN
happens to be False
, that may cause issues down the line.
However, the Dictionary
succeeds in performing the lookup and other operations work correctly as well.
The question here is really why you need it in the first place?
Paraphrasing from https://github.com/dotnet/corefx/blob/master/src/Common/src/CoreLib/System/Single.cs;
public const float NaN = (float)0.0 / (float)0.0;
public static unsafe bool IsNaN(float f) => f != f;
public int CompareTo(object? value){
...
if (m_value < f) return -1;
if (m_value > f) return 1;
if (m_value == f) return 0;
if (IsNaN(m_value))
return IsNaN(f) ? 0 : -1;
else // f is NaN.
return 1;
}
public bool Equals(float obj)
{
if (obj == m_value)
{
return true;
}
return IsNaN(obj) && IsNaN(m_value);
}
public override int GetHashCode()
{
int bits = Unsafe.As<float, int>(ref Unsafe.AsRef(in m_value));
// Optimized check for IsNan() || IsZero()
if (((bits - 1) & 0x7FFFFFFF) >= 0x7F800000)
{
// Ensure that all NaNs and both zeros have the same hash code
bits &= 0x7F800000;
}
return bits;
}
You can see that NaN requires special handling in each of these cases. The standard IEEE representation leaves most bits undefined, and defines special cases for comparisons even if those bit values are identical.
However you can also see that both GetHashCode()
&& Equals()
treat two NaN's as equivalent. So I believe that using NaN as a dictionary key should be fine.
It's bad idea to use float as key of Dictionary.
In theory you can do it. But when you work with float\double\decimal you shoud use some Epsilon to compare 2 values. Use formula like this:
abs(a1 - a2) < Epsilon
It's need due to rounding of float in operations and existing of irrational numbers. For example how you will compare with PI or sqrt(2)?
So, on this case using float as dictionary key is bad idea.