C++ c++;从3个浮点值生成无序_映射的键

C++ c++;从3个浮点值生成无序_映射的键,c++,floating-point,key,unordered-map,C++,Floating Point,Key,Unordered Map,我真的不明白: 我正在读取一个二进制文件中的三个浮点值。 将此点保存在无序的地图中 因此,我尝试从这3个浮点值中创建一个键: 第一个意图: 只需使用精确的位作为键: unordered_map<string, vector<float>> points; string vecToKey( float* a ) { char bytes[12]; memcpy(bytes, a, 12); return string(bytes); } 无序地图点; 字符串向量(浮点*a

我真的不明白:

我正在读取一个二进制文件中的三个浮点值。 将此点保存在无序的地图中

因此,我尝试从这3个浮点值中创建一个键:

第一个意图: 只需使用精确的位作为键:

unordered_map<string, vector<float>> points;
string vecToKey( float* a ) {
char bytes[12];
memcpy(bytes, a, 12);
return string(bytes);
}
无序地图点;
字符串向量(浮点*a){
字符字节[12];
memcpy(字节,a,12);
返回字符串(字节);
}
关键是,我肯定想用这种方式删除相同的点 但是

在一个示例项目中,读数约为21374点 地图结果大小=10640点

使用以下方法作为键创建会产生正确的结果 10 687分

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();
}
stringvec3tokey(浮点a[3]){
浮动a1[3];
a1[0]=a[0];
a1[1]=a[1];
a1[2]=a[2];
细流ss;
boost::archive::text\u oarchive oa(ss);

oa将索引更改为整数类型,例如
unsigned int
。请尝试以下代码:

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;
}
// 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;
unsigned int-vec3toKey(浮点a[3])
{
unsigned char*in=reinterpret_cast(a);
无符号整数ret=2654435761u;
对于(int i=0;i<(3*sizeof(float));+i)
ret=(ret*2654435761u)^*in++;
返回ret;
}

通用容器可以使用任何类型作为键。在这个应用程序中,您肯定有某种类型的point类。这应该是您的键

另外,为了使用自己的类型,您需要重载哈希函数(感谢DavidSchwartz)。此问题解决了以下问题:

PS:如果你没有点结构或类,你可能需要一个:p

string vecToKey( float* a ) {
  char bytes[12];
  memcpy(bytes, a, 12);
  return string(bytes);
}
您正在使用的字符串构造函数在第一个空字节处停止。浮点值可能包含空字节。因此,字符串可能无法准确表示三个浮点。在其中插入一个断言可以看出:

  string s(bytes);
  assert(s.size() == sizeof bytes);
  return s;
}
另一个问题是
字节
可能不包含空字节,程序可能会将随机垃圾复制到字符串中,或者表现出未定义的行为

我建议您不要这样滥用字符串。您想要一个三个浮点数的键,所以请使用一个正好表示以下内容的键:
std::array
。或者最好使用一个“Point”类,因为这是三个浮点数所表示的

由于没有用于数组的内置哈希函数,因此可以使用如下内容:

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;
}
// 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;
//取自http://stackoverflow.com/questions/6899392/generic-hash-function-for-all-stl-containers
模板
内联无效哈希组合(标准::大小t&seed,常量t&v)
{
散列哈希器;
seed^=hasher(v)+0x9e3779b9+(seed>2);
}
结构哈希器{
size_t运算符()(标准::数组常量&v){
size_t h=std::hash()(v[0]);
hash_组合(h,v[1]);
hash_组合(h,v[2]);
返回h;
}
};
std::无序地图;

我试图使用@bames53解决方案,但遇到了一些编译问题。在考虑@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;

  }
#包括
#包括
#包括
#包括
模板结构哈希器{
typedef typename C::value_type value_type;
内联std::size\u t运算符()(常量C&C)常量{
std::size\u t seed=0;
for(typename C::const_iterator it=C.begin();it!=C.end();++it){
散列哈希器;
seed^=hasher(*it)+0x9e3779b9+(seed>2);
}
返回种子;
}
};
int main()
{
std::无序地图E;
std::数组t1={34,56,78};
std::向量结果;
结果:推回(45);
E[t1]=结果;
}

如果你关心速度,不要使用
std::string
s作为开始键。第一段代码已断开。如何使用
string(字节)
知道输出字符串应该有多少字节吗?第二种方法需要很长时间,因为它必须将浮点值转换为文本。@DavidSchwartz如果
字节长度为13并且初始化为零,第一种方法可以工作,尽管这仍然是个坏主意。
字符串(字节)如何工作
知道它的大小是13吗?第一个例子也被某些浮点数打断,这些浮点数在其模式中以字节形式包含零。看起来对于无序映射,您需要==重载,对吗?您需要一个比较函数和一个散列函数来使用某些内容作为无序映射的键类。