NaN是关联容器的有效键值吗? [英] Is NaN a valid key value for associative containers?

查看:151
本文介绍了NaN是关联容器的有效键值吗?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

考虑以 double 键入的C ++中的有序和无序关联容器。

Consider the ordered and unordered associative containers in C++ keyed on double.

NaN 有效的密钥类型?

对于有序容器,我应该说不,因为它不遵守严格的弱排序。

With ordered containers, I should say "no", because it does not respect the strict weak ordering.

对于无序容器,我不知道。

With unordered containers, I have no idea.

这里是在GCC 4.6.2中发生的: p>

Here's what happens in GCC 4.6.2:

#include <map>
#include <unordered_map>

#include <cmath>

#include <iostream>
#include <prettyprint.hpp>

int main()
{
  typedef std::map<double, int> map_type; // replace by "unorderd_map"

  map_type dm;
  double d = std::acos(5); // a good nan

  dm[d] = 2;
  dm[d] = 5;
  dm[d] = 7;

  std::cout << "dm[NaN] = " << dm[d] << ", dm = " << dm << std::endl;
}

对于有序映射,我得到:

For the ordered map, I get:

dm[NaN] = 7, dm = [(nan, 7)]

对于无序映射,我得到:

For the unordered map, I get:

dm[NaN] = 0, dm = [(nan, 0), (nan, 7), (nan, 5), (nan, 2)]


b $ b

因此,在有序映射中,所有NaN都被视为相同,这是我的期望,虽然看起来NaN会违反要求。对于无序映射,然而,我不能再次检索元素,所有NaNs是不同的。这也不是我的期望。

So in the ordered map, all NaNs are treated the same, which is what I expect, although it seemed like NaN would violate the requirements. For the unordered map, however, I can never retrieve an element again, and all NaNs are different. This is also not what I would expect.

标准对这件事情要说什么吗?

Does the standard have to say anything on this matter?

更新:由于下面的很好的答案,注意 std :: map 将打破,如果你插入任何其他

Update: Thanks to the great answers below, note that the std::map will break if you insert anything else into it once a NaN is in it.

(非常感谢其他语言如何处理关联容器中的浮点键)。

(I'd be very grateful for comments on how other languages handle floating point keys in associative containers.)

推荐答案

它们都被标准禁止。

容器,严格弱订单的定义(25.4 / 4)说:

For the (ordered) associative containers, the definition of strict weak order (25.4/4) says:


如果我们定义 equiv b) as !comp(a,b)&& !comp(b,a),那么
需求是 comp equiv 都是传递关系...
equiv(a,b)&& equiv(b,c)表示 equiv(a,c)

If we define equiv(a, b) as !comp(a, b) && !comp(b, a), then the requirements are that comp and equiv both be transitive relations ... equiv(a, b) && equiv(b, c) implies equiv(a, c)


b $ b

对于a = 0.0,b = NaN,c = 1.0,comp = std :: less< double>()

对于无序容器,23.2.5 / 3说等式谓词 Pred 引起类型<$的值的等价关系c $ c>键。等价关系是反射性的,并且 std :: equal_to< double>()(NaN,NaN) / code>不是一个等价关系。

For the unordered containers, 23.2.5/3 says that the equality predicate Pred "induces an equivalence relation on values of type Key". Equivalence relations are reflexive, and std::equal_to<double>()(NaN,NaN) is false, so equal_to<double>() is not an equivalence relation.

顺便说一句,在double上键入容器是有点可怕的,略有恐怖。你永远不知道你要在最不重要的位置得到什么。

By the way, keying containers on a double is slightly scary in the same way that comparing doubles for equality is always slightly scary. You never know what you're going to get in the least significant bit.

我一直认为有点奇怪的是,标准表达的要求键 ,而不是根据添加到容器的实际键值。我相信你可以选择读这个不保证 map< double,int> 已定义的行为,如果实现支持NaNs,无论你是否实际添加NaN到一个实例。在实践中,虽然, std :: map 的实现不能以某种方式让它的后面口袋中的 NaN 为了比较它,它只比较传递给实例的键值。所以应该是OK(如果有点吓人),如果你避免添加NaNs。

Something I've always considered a little odd is that the standard expresses the requirements in terms of the key type, not in terms of the actual key values added to the container. I believe you could choose to read this as not guaranteeing that map<double, int> has defined behaviour at all if the implementation supports NaNs, regardless of whether you actually add a NaN to an instance or not. In practice, though, an implementation of std::map cannot somehow conjure a NaN out of its back pocket and try to compare it, it only ever compares key values passed to the instance. So it should be OK (if slightly scary) provided you avoid adding NaNs.


我非常感谢关于其他语言处理
关联容器中的浮点键

I'd be very grateful for comments on how other languages handle floating point keys in associative containers

在Python中进行一些快速实验(其中 / code>和 dict 是无序的关联容器,它们通过引用来保存键和值)表明NaN被视为值不等的对象,即使它们同一NaN,但相同的nan 对象可以通过标识再次找到。就我所见,容器似乎没有被包含多个nans,或nans和其他值的混合物扰乱:

A few quick experiments in Python (where set and dict are unordered associative containers which hold keys and values by reference) suggest that NaNs are treated as objects that are unequal in value even if they're "the same NaN", but the same nan object can be found again by identity. As far as I've seen, the containers don't seem to be disturbed by containing multiple nans, or a mixture of nans and other values:

>>> thing = set()
>>> nan = float('nan')
>>> nan
nan
>>> thing.add(nan)
>>> thing.add(nan)
>>> thing
set([nan])

>>> thing = dict()
>>> thing[nan] = 1
>>> thing[nan] = 2
>>> thing[nan]
2
>>> nan2 = float('nan')
>>> thing[nan2] = 3
>>> thing
{nan: 2, nan: 3}

>>> thing = set()
>>> thing.add(nan)
>>> thing.add(nan2)
>>> thing
set([nan, nan])

>>> thing = dict()
>>> thing[nan] = 1
>>> thing[nan2] = 2
>>> thing[0] = 3
>>> thing
{nan: 1, nan: 2, 0: 3}
>>> thing.keys()
[nan, nan, 0]
>>> thing.values()
[1, 2, 3]
>>> thing[0]
3
>>> thing[1]
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
KeyError: 1

这篇关于NaN是关联容器的有效键值吗?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆