为了在3d空间中快速找到一堆平面实体中的共面实体,我想创建一个从3d平面到位于该平面中的实体集的映射(估计最大约1000个平面和~100000个实体)
我可以创建自己的自定义类来表示3D平面键,但基本上这个类需要(数学上)四个双精度来唯一地标识一个平面:法线向量的3个坐标和平面上指定点的一个坐标。所以我们有:
struct Plane3d
{
double n_x, n_y, n_z;
double u; // (u*n_x, u*n_y, u*n_z) is a point on the plane
// some constructors etc.
}
这四个双打是每次从所考虑的实体计算出来的,因此必须考虑舍入误差和浮点比较问题。假设我已计算出合适的(相对)误差容差:
const double EPSILON;
然而,我不想逐一比较所有实体对的共面性(在O(n ^ 2)时间内进行分类),而是创建一个地图来对我的实体进行分类。
最理想的是unordered_map(在O(n)时间内创建):
unordered_map<Plane3d, vector<Entity>, PlaneHash, PlaneEquality> mapping;
这需要编写两个仿函数:PlaneEquality没问题,但是......
另一种选择是使用法线贴图(在O(n log n)时间内仍然创建)
map<Plane3d, vector<Entity>, PlaneCompare> mapping;
PlaneCompare仿函数听起来可行,我可以使用四个双打的词典编排,并使用EPSILON
检查每个“小于”。但我还有几个问题:
!PlaneCompare(p1,p2) && !PlaneCompare(p2,p1)
决定。如果我使用了字典顺序,这应该等同于具有容错性的直接相等测试,但这不是更慢吗?答案 0 :(得分:3)
“是否可以为四个双打(或者甚至只是常规双精度)编写一个Hash函数,它考虑了比较误差容差。”
不,不是。
这听起来像是一个非常明确的陈述,我怎么能这么肯定?
假设你想要0.00001的公差。价值无关紧要,我们只是以它为例。这意味着对于这个哈希函数:
这样他们就可以被认为是平等的。但它也意味着:
出于同样的原因,
...依此类推,达到最高可能的双倍价值 - 实际上是无限的。低于1的值也是如此。
所以任何允许容差的哈希函数都必须为所有值返回相同的哈希值,这使得它无用。
P.S。实际上推荐一种有效的方法,四维四叉树(技术上像sedecimtree)可能是最好的。
答案 1 :(得分:0)
你可以围绕你的双打,例如范围[n - epsilon, n + epsilon)
中的所有值都舍入为n
n mod epsilon == 0
,并对其进行哈希处理。在这种情况下,您的close值将具有相同的哈希值。
如何更好地哈希4个双打取决于你的情况,但即使总结它们也足够好。