Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/cplusplus/145.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 提供一个好的散列函数_C++_Stl_Performance Testing_Unordered Set_Hash Function - Fatal编程技术网

C++ 提供一个好的散列函数

C++ 提供一个好的散列函数,c++,stl,performance-testing,unordered-set,hash-function,C++,Stl,Performance Testing,Unordered Set,Hash Function,在我的初始问题(详细的实验调查)中:我使用未排序集管理随机N维浮点数组,并使用我的初始(可能设计糟糕的哈希函数),得到了非常奇怪的行为: #包括 #包括 #包括 #包括 #包括 常数int N=3;//阵列的维数 std::数组getRandomArray(){ //引擎和分布保持状态,因此定义为静态 静态std::默认\u随机\u引擎e;//引擎 静态std::均匀实分布d(0,1);//分布 std::数组ret; 对于(尺寸i=0;i

在我的初始问题(详细的实验调查)中:我使用未排序集管理随机N维浮点数组,并使用我的初始(可能设计糟糕的哈希函数),得到了非常奇怪的行为:

#包括
#包括
#包括
#包括
#包括
常数int N=3;//阵列的维数
std::数组getRandomArray(){
//引擎和分布保持状态,因此定义为静态
静态std::默认\u随机\u引擎e;//引擎
静态std::均匀实分布d(0,1);//分布
std::数组ret;
对于(尺寸i=0;istd::cout您的程序显示未定义的行为(未初始化
std::size\u t ret
变量除外)

首先,
ArrayEqual
不会产生等价关系。它是不可传递的-存在三个数组
a
b
c
,使得
a
b
足够接近,
b
c
足够接近,但
a
不够接近到
c

其次,
ArrayHash
可能不会为声明相等的两个数组返回相同的哈希值


这两个都是
std::unordered_set

的模板参数的先决条件。您是否检查了给定数组的实际哈希值是多少?使用-O3构建时是否会发生变化?是否查看了一些可管理数量的随机数组的哈希值分布?是否-O3选择了不同的默认随机引擎?
std::size\u t ret;
你意识到事情是不确定的吗?因此后续循环的
ret+=std::hash()(elem);
几乎一文不值。所以,是的,我会说它设计得很糟糕。@WhozCraig谢谢,真的是这样(我感到羞耻)!初始化
std::size\u t ret=0后,我去掉了第二个奇怪的东西。谢谢,我完全同意你的两个观点。现在的实际问题是如何修复它们。你需要定义等价类,并坚持使用它们。例如,你可以将空间分成一个N维网格,
1e-6
单位在一边。所有点如果落入同一单元格,则被
ArrayEqual
视为等效。为类选择一个代表(例如,单元格的中心或具有最小坐标的角),并让
ArrayHash
为单元格中的每个点返回该代表的哈希值。
#include <iostream>
#include <chrono>
#include <random>
#include <array>
#include <unordered_set>

const int N = 3;  // Dimensionality of the arrays

std::array<double, N> getRandomArray() {
  // Engines and distributions retain state, thus defined as static
  static std::default_random_engine e;                    // engine
  static std::uniform_real_distribution<double> d(0, 1);  // distribution
  std::array<double, N> ret;
  for (size_t i = 0; i < N; ++i) {
    ret[i] = d(e);
  }
  return ret;
}

// Return Squared Euclidean Distance
template <typename InputIt1, typename InputIt2>
double EuclideanDistance2(InputIt1 beg1, InputIt1 end1, InputIt2 beg2) {
  double val = 0.0;
  while (beg1 != end1) {
    double dist = (*beg1++) - (*beg2++);
    val += dist*dist;
  }
  return val;
}

struct ArrayHash {  // Hash Function
  std::size_t operator() (const std::array<double, N>& arr) const {
    std::size_t ret = 0;
    for (const double elem : arr) {
      ret += std::hash<double>()(elem);
    }
    return ret;
  }
};

struct ArrayEqual {  // Equivalence Criterion
  bool operator() (const std::array<double, N>& arr1,
                          const std::array<double, N>& arr2) const {
    return EuclideanDistance2(arr1.begin(), arr1.end(), arr2.begin()) < tol*tol;
  }
 private:
  static constexpr double tol = 1e-6;  // Comparison tolerance
};


int main() {
  // create a unordered set of double arrays (usda)
  std::unordered_set<std::array<double, N>, ArrayHash, ArrayEqual> usda;
  // record start time
  auto start = std::chrono::steady_clock::now();
  // Generate and insert one hundred thousands new double arrays
  for (size_t i = 0; i < 100000; ++i) {
    // Get a new random double array (da)
    std::array<double, N> da = getRandomArray();
    usda.insert(da);
  }
  // record finish time
  auto end = std::chrono::steady_clock::now();
  std::chrono::duration<double> diff = end - start;
  std::cout << "Time to generate and insert unique elements into UNORD. SET: "
            << diff.count() << " s\n";
  std::cout << "unord. set size() = " << usda.size() << std::endl;
  return 0;
}