Project

General

Profile

Bug #13146

Float::NANs in Hashes are confusing (more than usual).

Added by yxhuvud (Linus Sellberg) almost 3 years ago. Updated over 2 years ago.

Status:
Rejected
Priority:
Normal
Assignee:
-
Target version:
-
ruby -v:
ruby 2.3.1p112
[ruby-core:79217]

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.

History

Updated by shevegen (Robert A. Heiler) over 2 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) over 2 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) over 2 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) over 2 years ago

Are you suggesting to make infinities and a NaN multiton?

Updated by nobu (Nobuyoshi Nakada) over 2 years ago

  • Description updated (diff)

Updated by sos4nt (Stefan Schüßler) over 2 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) over 2 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) over 2 years ago

I reported similar issue on bigdecimal.
I want to discuss this issue here.

https://github.com/ruby/bigdecimal/issues/31

Updated by nobu (Nobuyoshi Nakada) over 2 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) over 2 years ago

  • Status changed from Open to Rejected

You have to understand what NaN is, before playing with it.

Matz.

Also available in: Atom PDF