【问题标题】:std::map trick for comparing unrepresentable numbers?用于比较无法表示的数字的 std::map 技巧?
【发布时间】:2012-09-25 08:34:11
【问题描述】:

我想在 C++ std::map 中有一个用户定义的键。关键是具有最大值2^V 的整数集的二进制表示,所以我不能代表所有2^V 可能的值。我通过有效的二进制集表示来做到这一点,即uint64_t 的数组。

现在的问题是,要将这个用户定义的位集作为 std::map 中的键,我需要定义位集值之间的有效比较,但如果我的最大大小为 V=1000,那么我无法获得我可以比较的数字,更不用说将它们全部聚合,即2^1000 是不可表示的。

因此我的问题是,假设我有两个不同的集合(通过在我的 bitset 表示中设置正确的位)并且我无法表示最终数字,因为它会溢出:

id_1 = 2^0 + 2^1 + ... + 2^V

id_2 = 2^0 + 2^1 + ... + 2^V

是否有合适的转换可以产生我可以比较的值?我需要能够说id_1 < id_2,所以我想将指数总和转换为一个可表示的值,但要保持“小于”的不变量。我在考虑例如以巧妙的方式应用对数转换来保留“小于”。

这是一个例子:

set_1 = {2,3,4}; set_2 = {8}

id(set_1) = 2^2 + 2^3 + 2^4 = 28; id(set_2) = 2^8 = 256

id(set_1) < id(set_2)

完美!一个可以有{1,...,V}2^V 可能子集的通用集合怎么样?

【问题讨论】:

  • 你为什么不自己比较这些值呢?您将始终受到将ids 映射到非双射的有限整数的困扰。
  • 没错。每当您尝试从一组转换为较小的一组时,都会遇到冲突和不正确比较的机会。一点一点的比较似乎是要走的路。
  • 逐位比较并不能解决问题。假设您有一个 int64_t 数组,并且您走得越远,指数就会得到例如2^5000 不加总怎么能比较?我只是不明白怎么做。
  • “如何在不汇总的情况下进行比较” - 按字典顺序?
  • 不要使用uint64_t,除非您的应用程序绝对需要完全 64位。一般来说,使用uint_least64_t,因为uint64_t 不需要存在。

标签: c++ math hash stl map


【解决方案1】:

我通过有效的二进制集表示来做到这一点,即 uint64_t 数组。

假设通过键类型Key 的数据成员ra 访问此数组,并且两个数组的长度为N,那么您需要一个类似这样的比较器:

bool operator<(const Key &lhs, const Key &rhs) {
    return std::lexicographical_compare(lhs.ra, &lhs.ra[N], rhs.ra, &rhs.ra[N]);
}

这隐含地认为数组是大端的,即第一个 uint64_t 是最重要的。如果您不喜欢这样,这很公平,因为您可能已经考虑到您将V 位存储到数组中的任何顺序的相对重要性。 lexicographical_compare 没有什么神秘之处,所以只要看an example implementation 并根据需要进行修改。

这称为“字典顺序”。除了我使用uint64_t 而不是char 并且两个数组的长度相同之外,这是比较字符串的方式[*] - 实际上uint64_t 的使用并不重要,你可以在比较器中使用 std::memcmp 而不是比较 64 位块。 operator&lt; for strings 不能通过将整个字符串转换为整数来工作,你的比较器也不应该。

[*] 直到您使用特定于区域设置的排序规则。

【讨论】:

  • 你也可以使用std::lexicographical_compare,它就是这样做的。
  • @interjay:我从来没有,那一直都在那里。好的。
  • 谢谢!我实际上想到了字典顺序,但是使用了一个字符串,然后我认为拥有这么长的字符串是一种浪费……我不知道我可以直接对 uint64_t 数组进行字典顺序。谢谢!
  • @Giovanni:是的,字典顺序原则上适用于取自任何本身已排序的类型的值的任何序列(不一定是相同的长度)。 lexicographical_compare 在 C++ 中实现。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-01-05
  • 2017-07-28
  • 1970-01-01
  • 2014-05-10
  • 1970-01-01
相关资源
最近更新 更多