簡體   English   中英

如何通過對地圖嚴格的弱排序對數學向量進行排序?

[英]How do i sort mathematical vectors by strict weak ordering for a map?

我嘗試編寫一個std :: map <Vector3D,double>,其中colinear(並行或反並行)向量應該共享相同的密鑰。

作為比較函數,我使用以下函數(在isEqualEnough()中具有1e-9容差),這是我在std :: map使用(數學)向量創建的

struct Vector3DComparator 
{ 
    bool operator() (const Vector3D& lhsIn, const Vector3D& rhsIn) const
    {
        Vector3D lhs = lhsIn.absolute(); // make all members positive
        Vector3D rhs = rhsIn.absolute(); 

        if ((lhs.z < rhs.z)) 
            return true;

        if ((isEqualEnough(lhs.z, rhs.z)) 
            && (lhs.y < rhs.y)) 
            return true;

        if ((isEqualEnough(lhs.z, rhs.z)) 
            && (isEqualEnough(lhs.y, rhs.y))
            && (lhs.x < rhs.x))
            return true;

        return false;
    }
};

當我將一個立方體的法線插入我的地圖時,我應該得到3個不同的值(因為我不關心方向)但我得到4:

  • x = 1 y = 0 z = 0
  • x = 0 y = 1 z = 0
  • x = 0 y = 0 z = 1
  • x = 0 y = 2.2e-16 z = 1

比較函數在某種程度上是錯誤的,但每當我嘗試修復它時,我得到一個斷言告訴我“表達式:無效的比較器”。

有人發現錯誤嗎?

在數學上不可能對關系運算符使用容差並產生嚴格的弱排序。 任何類型的收斂標准都不能滿足排序算法和數據結構要求。 原因很簡單:使用容差的兩個值的不兼容性不會產生等價關系,因為它不是傳遞的 你可能有almostEqual(a, b)almostEqual(b, c)而且~almostEqual(a, c) 嘗試使用a=1.0; b=2.0; c=3.0; tolerance=1.5; a=1.0; b=2.0; c=3.0; tolerance=1.5; 您可以看一下這個答案: 浮點數=是否正常?

您仍然可以使用截斷,地板,屋頂或圓形函數在浮點數上定義等價關系。 讓我們定義例如less3(a, b)當且僅當floor(a * 8) < floor(b * 8)假設a和b是二進制浮點數並且不是NAN並且乘法不產生相同的有符號無窮大; 這比較a和b使用3位精度(十進制0.125)。 現在定義equiv3(a, b)當且僅當!less3(a, b) && ~less3(b, a) 可以證明, eqiv3(a, b)產生適當的等價關系。 由於less3是階次關系而equiv3是等價關系,因此less3是浮點數(不包括NAN)的嚴格弱階。 此外,在a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF你可以使用普通的<operator on floats回退。

將Julien Villemure-Fréchette的答案與@alterigel發布的鏈接結合起來,我的比較函數工作:

struct Vector3DComparator 
{ 
    bool operator() (const Vector3D& lhsIn, const Vector3D& rhsIn) const
    {
        int p = 100000; // precision factor

        Vector3D lhs = lhsIn.absolute(); // make all members positive
        Vector3D rhs = rhsIn.absolute();

        auto lhsTied = std::tie((int)(lhs.x * p), (int)(lhs.y * p), (int)(lhs.z * p));
        auto rhsTied = std::tie((int)(rhs.x * p), (int)(rhs.y * p), (int)(rhs.z * p));
        return lhsTied < rhsTied;
    }
};

請注意:此代碼包含錯誤的樣式,如c風格的演員表,錯誤的命名等等。 我的函數和類與此處發布的函數和類不同。 我只是將所有東西都剝離了以使其易於理解。

編輯:

我注意到還有兩個錯誤:

第一:它並不總是適用於幾乎相同的載體。 根據@tetorea對我的問題的最后評論我改變了函數,總是得到非常相似的值。 我使用點積,因為它對於平行向量是±1(或至少接近)。

第二:.absolute()不起作用,因為有了這個函數,兩個向量(-1,1,0)和(1,1,0)被認為是平行的,它們顯然不是。

在下面的代碼中,您可以找到更正的版本:

struct Vector3DComparator 
{ 
    bool operator() (const Vector3D& lhs, const Vector3D& rhs) const
    {
        if (isEqualEnough(fabs(lhs * rhs), 1.0)) // dot product
            return false;

        int p = 100000; // precision factor

        auto lhsTied = std::tie((int)(lhs.x * p), (int)(lhs.y * p), (int)(lhs.z * p));
        auto rhsTied = std::tie((int)(rhs.x * p), (int)(rhs.y * p), (int)(rhs.z * p));

        return lhsTied < rhsTied;
    }
};

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM