简体   繁体   English

c ++从3个浮点值生成unordered_map的键

[英]c++ generate key for unordered_map from 3 floats values

i really dont get it: 我真的不明白:

i am reading points, each holds 3 float values, out of a binary file. 我正在读取点,每个持有3个浮点值,从二进制文件。 Saving this points in an unordered_map 将此点保存在unordered_map中

therefore i try to create a key out of these 3 float values: 因此我尝试从这3个浮点值中创建一个键:

first intention: just use the exact bits as key: 第一个意图:只使用确切的位作为关键:

unordered_map<string, vector<float>> points;
string vecToKey( float* a ) {
char bytes[12];
memcpy(bytes, a, 12);
return string(bytes);
}

the point is that i definitely want to eleminate same points this way but 关键是我绝对想以这种方式消除相同的点数

in an example project reading about 21374 points the map result size = 10640 points 在示例项目中,读取约21374点,地图结果大小= 10640点

using following method as key creation results in the proper result of 10687 points 使用以下方法作为密钥创建导致10687点的正确结果

string vec3ToKey( float a[3] ) {
float a1[3];
a1[0] = a[0];
a1[1] = a[1];
a1[2] = a[2];
stringstream ss;
boost::archive::text_oarchive oa(ss);
oa << a1;
return ss.str();
}

the problem is the speed. 问题是速度。 second method needs about 16 seconds and first method just 1-2 seconds... i just cant explane myself why there even is a difference ... 第二种方法需要大约16秒,第一种方法只需1-2秒...我只是不能解释自己为什么会有差异......

i appreciate every idea :) 我很欣赏每一个想法:)

string vecToKey( float* a ) {
  char bytes[12];
  memcpy(bytes, a, 12);
  return string(bytes);
}

The string constructor you're using stops at the first null byte. 您正在使用的字符串构造函数在第一个空字节处停止。 Floating point values can contain null bytes. 浮点值可以包含空字节。 So the string is probably not accurately representing the three floats. 因此字符串可能无法准确表示三个浮点数。 You can see by sticking an assert in there: 你可以通过在那里插入一个断言来看到:

  string s(bytes);
  assert(s.size() == sizeof bytes);
  return s;
}

Another problem is that bytes might not contain a null byte, and the program may copy random garbage into the string or otherwise exhibit undefined behavior. 另一个问题是bytes可能包含空字节,并且程序可能会将随机垃圾复制到字符串中或以其他方式显示未定义的行为。

I would recommend that you just not try to abuse string this way. 我建议您不要试图以这种方式滥用字符串。 You want a key that's three floats, so use a key that represents exactly that: std::array<float,3> . 你想要一个三个浮点数的键,所以使用一个代表它的键: std::array<float,3> Or better yet use a 'Point' class since that's what the three floats represent. 或者更好的是使用'Point'类,因为这是三个浮点数所代表的。

Since there's no built in hash function for arrays you can use something like this: 由于数组没有内置的哈希函数,你可以使用这样的东西:

// taken from http://stackoverflow.com/questions/6899392/generic-hash-function-for-all-stl-containers
template <class T>
inline void hash_combine(std::size_t & seed, const T & v)
{
  std::hash<T> hasher;
  seed ^= hasher(v) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
}

struct Hasher {
    size_t operator() (std::array<float,3> const &v) {
        size_t h = std::hash<float>()(v[0]);
        hash_combine(h,v[1]);
        hash_combine(h,v[2]);
        return h;
    }
};


std::unordered_map<std::array<float,3>,vector<float>,Hasher> map;

Change the index to an integer type, say unsigned int . 将索引更改为整数类型,例如unsigned int Try code more like this: 尝试更像这样的代码:

unsigned int vec3toKey( float a[3] )
{
   unsigned char *in = reinterpret_cast<unsigned char>(a);
   unsigned int ret = 2654435761u;
   for(int i = 0; i < (3 * sizeof(float)); ++i)
     ret = (ret * 2654435761u) ^ *in++;
   return ret;
}

A generic container can use any type as the key. 通用容器可以使用任何类型作为键。 Surely you have some kind of point class in this application. 当然,你在这个应用程序中有一些点类。 That should be your key. 这应该是你的关键。

Aparently you'll need to overload the hashing function in order to use your own type (thanks DavidSchwartz). 显然你需要重载散列函数才能使用你自己的类型(感谢DavidSchwartz)。 This question addresses that: 这个问题解决了:

C++ unordered_map user defined type C ++ unordered_map用户定义的类型

PS: If you don't have a point struct or class, you probably want one :p PS:如果你没有点结构或类,你可能需要一个:p

I was trying to use @bames53 solution but got some compilation issues. 我试图使用@ bames53解决方案,但得到了一些编译问题。 While considering this answer and what @bames53 is given here is the final version I have 在考虑这个答案时 ,@ bames53在这里给出的是我的最终版本

  #include <iostream>
  #include <string>
  #include <vector>
  #include <unordered_map>


  template <typename C> struct Hasher{
                      typedef typename C::value_type value_type;
                      inline std::size_t operator() (const C &c) const{
                          std::size_t seed = 0;
                          for(typename C::const_iterator it = c.begin(); it != c.end(); ++it){
                              std::hash<value_type> hasher;
                              seed ^= hasher(*it) + 0x9e3779b9 + (seed << 6) + (seed >> 2);
                          }
                          return seed;
                      }
  };

  int main()
  {

              std::unordered_map<std::array<float, 3>, std::vector<float>, Hasher<std::array<float, 3>>> E;
                  std::array<float, 3> t1 = {34, 56,78};
                  std::vector<float> result;
                  result.push_back(45);
                  E[t1] = result;

  }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM