Bug #13146
closedFloat::NANs in Hashes are confusing (more than usual).
Description
test = {Float::NAN => 1, -Float::NAN => 2}
=> {NaN=>1, NaN=>2}
test.values_at(Float::NAN, -Float::NAN)
=> [1, nil]
I don't know what the correct behaviour ought to be, but it seems inconsistent to create a hash with two elements but not be able to extract both values.
Updated by shevegen (Robert A. Heiler) almost 8 years ago
This is actually interesting altogether.
First that Float::NAN becomes NaN in the display; this is the first surprise to me.
But second, that we have seemingly the same key twice (???), at the least in the display.
{NaN=>1, NaN=>2}
Should not the second key be a negative one? I guess NaN does not specify this as any more
accurate but it treats them as two different entries in the hash regardless, or? That is a
bit confusing to me.
I have no idea if this is a correct behaviour or not but to me this was a surprise to see.
Some docu can be found here:
http://ruby-doc.org/core-2.0.0/Float.html
"NAN: An expression representing a value which is “not a number”."
To me I guess the surprise is that NAN in itself should be unique? But in hashes you can
store different NANs? Then again I probably do not understand anything anyway. :)
Updated by yxhuvud (Linus Sellberg) almost 8 years ago
Robert A. Heiler wrote:
To me I guess the surprise is that NAN in itself should be unique?
NaN is defined by IEEE to fail equality tests with all floats (including itself), so it could be argued it is more unique than any other value. It could certainly be argued that as each NAN fail equality tests, indexing by NAN should never find anything in a hash.
Updated by sos4nt (Stefan Schüßler) almost 8 years ago
Somehow, using -Float::NAN
(for example in a hash or array) results in new objects being created:
-Float::NAN.object_id
#=> -70362448918680
[-Float::NAN, -Float::NAN, -Float::NAN].map(&:object_id)
#=> [70362448604580, 70362448604520, 70362448604500]
As a result, these objects are no longer equal. It seems like -Float::NAN
is duplicated upon assignment:
a = -Float::NAN
b = -Float::NAN
a == b #=> false
Float::NAN
on the other hand behaves as expected (always the same object):
Float::NAN.object_id
#=> 70362448918680
[Float::NAN, Float::NAN, Float::NAN].map(&:object_id)
#=> [70362448918680, 70362448918680, 70362448918680]
The same happens with -Float::INFINITY
.
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
Are you suggesting to make infinities and a NaN multiton?
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
- Description updated (diff)
Updated by sos4nt (Stefan Schüßler) almost 8 years ago
Nobuyoshi Nakada wrote:
Are you suggesting to make infinities and a NaN multiton?
I don't know how these are implemented, but I'd expect -Float::NAN
to work like Float:NAN
in that regard. If I'm not mistaken, theres only one Float::NAN
instance. Having multiple instances of -Float::NAN
on the other hand is very confusing. Especially because they are not even equal:
[-Float::NAN, -Float::NAN, -Float::NAN].uniq
#=> [NaN, NaN, NaN]
Updated by yxhuvud (Linus Sellberg) almost 8 years ago
Nobuyoshi Nakada wrote:
Are you suggesting to make infinities and a NaN multiton?
One alternative is to copy the approach given here: https://research.swtch.com/randhash
TLDR:
1: NaN is given a random hash (to avoid hash key collisions).
2: Hash insertion work, but never overwrite - always adds a new key.
3: Lookup never finds anything
4: Iteration over the values works.
Updated by yui-knk (Kaneko Yuichiro) almost 8 years ago
I reported similar issue on bigdecimal.
I want to discuss this issue here.
Updated by nobu (Nobuyoshi Nakada) almost 8 years ago
Linus Sellberg wrote:
1: NaN is given a random hash (to avoid hash key collisions).
2: Hash insertion work, but never overwrite - always adds a new key.
3: Lookup never finds anything
4: Iteration over the values works.
It doesn't work right now as you expect, since the hash assumes same elements are always equal, regardless their hash values.
Updated by matz (Yukihiro Matsumoto) almost 8 years ago
- Status changed from Open to Rejected
You have to understand what NaN is, before playing with it.
Matz.