4

私は本当にそれを取得しません:

私はポイントを読んでいます。それぞれがバイナリファイルから3つのfloat値を保持しています。このポイントをunordered_mapに保存する

したがって、これら3つのfloat値からキーを作成しようとします。

最初の意図:正確なビットをキーとして使用するだけです:

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

ポイントは、私は間違いなくこの方法で同じポイントを排除したいということですが

約21374ポイントを読み取るプロジェクトの例では、マップ結果のサイズ=10640ポイント

キーの作成として次の方法を使用すると、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();
}

問題は速度です。2番目の方法は約16秒、最初の方法は1〜2秒必要です...私は自分自身を説明することができません。なぜ違いがあるのか​​...

私はすべてのアイデアに感謝します:)

4

5 に答える 5

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

使用している文字列コンストラクターは、最初のnullバイトで停止します。浮動小数点値にはnullバイトを含めることができます。したがって、文字列はおそらく3つのフロートを正確に表していない可能性があります。そこにアサーションを貼り付けることで確認できます。

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

もう1つの問題は、nullバイトが含まれていないbytes可能性があり、プログラムがランダムなガベージを文字列にコピーしたり、未定義の動作を示したりする可能性があることです。

このように文字列を乱用しようとしないことをお勧めします。3つのフロートであるキーが必要なので、それを正確に表すキーを使用しますstd::array<float,3>。または、「Point」クラスを使用することをお勧めします。これは、3つのfloatが表すものだからです。

配列には組み込みのハッシュ関数がないため、次のようなものを使用できます。

// 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;
于 2012-05-29T18:36:26.837 に答える
1

インデックスを整数型に変更します。たとえば、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;
}
于 2012-05-29T18:25:16.930 に答える
0

汎用コンテナは、任意のタイプをキーとして使用できます。確かに、このアプリケーションにはある種のポイントクラスがあります。それがあなたの鍵になるはずです。

どうやら、独自の型を使用するには、ハッシュ関数をオーバーロードする必要があります(DavidSchwartzに感謝)。この質問はそれに対処します:

C++unordered_mapユーザー定義型

PS:ポイント構造体またはクラスがない場合は、おそらく1つ必要です:p

于 2012-05-29T18:27:33.793 に答える
0

http://www.boost.org/doc/libs/1_49_0/doc/html/hash/combine.html

于 2012-05-29T18:45:24.663 に答える
0

@ 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;

  }
于 2019-07-18T09:21:47.140 に答える