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












3















I try to write a std::map< Vector3D, double > where colinear (parallel or anti-parallel) vectors should share the same key.



As a compare function I use the following function (with a 1e-9 tolerance in isEqualEnough()) that I created with the help of Using a (mathematical) vector in a 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;
}
};


When I insert the normals of a cube into my map I should get 3 different values (because I don't care about the direction) but I get 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


The compare function is somehow wrong but whenever I try to fix it I get an assert telling me "Expression: invalid comparator".



Anyone spots the mistake?










share|improve this question




















  • 1





    Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

    – alter igel
    Nov 22 '18 at 20:02











  • @alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

    – jaba
    Nov 22 '18 at 20:07











  • maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

    – tetorea
    Nov 22 '18 at 20:25











  • @tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

    – jaba
    Nov 22 '18 at 20:28











  • @alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

    – jaba
    Nov 22 '18 at 20:30


















3















I try to write a std::map< Vector3D, double > where colinear (parallel or anti-parallel) vectors should share the same key.



As a compare function I use the following function (with a 1e-9 tolerance in isEqualEnough()) that I created with the help of Using a (mathematical) vector in a 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;
}
};


When I insert the normals of a cube into my map I should get 3 different values (because I don't care about the direction) but I get 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


The compare function is somehow wrong but whenever I try to fix it I get an assert telling me "Expression: invalid comparator".



Anyone spots the mistake?










share|improve this question




















  • 1





    Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

    – alter igel
    Nov 22 '18 at 20:02











  • @alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

    – jaba
    Nov 22 '18 at 20:07











  • maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

    – tetorea
    Nov 22 '18 at 20:25











  • @tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

    – jaba
    Nov 22 '18 at 20:28











  • @alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

    – jaba
    Nov 22 '18 at 20:30
















3












3








3








I try to write a std::map< Vector3D, double > where colinear (parallel or anti-parallel) vectors should share the same key.



As a compare function I use the following function (with a 1e-9 tolerance in isEqualEnough()) that I created with the help of Using a (mathematical) vector in a 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;
}
};


When I insert the normals of a cube into my map I should get 3 different values (because I don't care about the direction) but I get 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


The compare function is somehow wrong but whenever I try to fix it I get an assert telling me "Expression: invalid comparator".



Anyone spots the mistake?










share|improve this question
















I try to write a std::map< Vector3D, double > where colinear (parallel or anti-parallel) vectors should share the same key.



As a compare function I use the following function (with a 1e-9 tolerance in isEqualEnough()) that I created with the help of Using a (mathematical) vector in a 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;
}
};


When I insert the normals of a cube into my map I should get 3 different values (because I don't care about the direction) but I get 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


The compare function is somehow wrong but whenever I try to fix it I get an assert telling me "Expression: invalid comparator".



Anyone spots the mistake?







c++ stdmap strict-weak-ordering






share|improve this question















share|improve this question













share|improve this question




share|improve this question








edited Nov 22 '18 at 21:44







jaba

















asked Nov 22 '18 at 19:54









jabajaba

377215




377215








  • 1





    Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

    – alter igel
    Nov 22 '18 at 20:02











  • @alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

    – jaba
    Nov 22 '18 at 20:07











  • maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

    – tetorea
    Nov 22 '18 at 20:25











  • @tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

    – jaba
    Nov 22 '18 at 20:28











  • @alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

    – jaba
    Nov 22 '18 at 20:30
















  • 1





    Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

    – alter igel
    Nov 22 '18 at 20:02











  • @alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

    – jaba
    Nov 22 '18 at 20:07











  • maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

    – tetorea
    Nov 22 '18 at 20:25











  • @tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

    – jaba
    Nov 22 '18 at 20:28











  • @alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

    – jaba
    Nov 22 '18 at 20:30










1




1





Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

– alter igel
Nov 22 '18 at 20:02





Your comparator should not be modifying the two objects. What exactly does lhs.absolute(); do? Also, take a look at this: stackoverflow.com/questions/6218812/…

– alter igel
Nov 22 '18 at 20:02













@alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

– jaba
Nov 22 '18 at 20:07





@alterigel absolute() makes x,y and z positive. Also he is not really changing them, I just messed up my minimal example. I will edit it.

– jaba
Nov 22 '18 at 20:07













maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

– tetorea
Nov 22 '18 at 20:25





maybe I'm missing something obvious... but your comparator only test if lhs is inferior to rhs (=sorting the key), not if they are equal. Where is the code to compute your map key?

– tetorea
Nov 22 '18 at 20:25













@tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

– jaba
Nov 22 '18 at 20:28





@tetorea The map key is the lhs vector. And if they are equal enough they should share the same key. I insert into the map with myMap[vector.absolute()] += faceArea;

– jaba
Nov 22 '18 at 20:28













@alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

– jaba
Nov 22 '18 at 20:30







@alterigel I like the solution from the link but then I am not able to make values identical in the map that are really close because tie will compare the double values without precision. This will cause what I have now that 1e-16 and 0 are different.

– jaba
Nov 22 '18 at 20:30














2 Answers
2






active

oldest

votes


















7














It is mathematically impossible to use a tolerance with relational operators and yield a strict weak ordering. Any kind of convergence criterion will fail to satisfy ordering algorithms and data structures requirements. The reason is very simple: the incompatibility of two values, using a tolerance, doesn't yield an equivalence relation since it is not transitive. You may have almostEqual(a, b) and almostEqual(b, c) and yet ~almostEqual(a, c). Try this using a=1.0; b=2.0; c=3.0; tolerance=1.5;. You may look at this answer: Is floating-point == ever OK?.



You may still define an equivalence relation on floats using truncation, floor, roof, or round kind of functions. Let's define for example less3(a, b) if and only if floor(a * 8) < floor(b * 8) assuming a and b are binary floats and are not NAN and multiplications doesn't yield both the same signed infinite; this compares a and b using 3 bits of precision (0.125 in decimal). Now define equiv3(a, b) if and only if !less3(a, b) && ~less3(b, a). It can be shown that eqiv3(a, b) yields an appropriate equivalence relation. Since less3 is an order relation and equiv3 is an equivalence relation, then less3 is a strict weak order on floats (excluding NANs). Furthermore, in the case a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF you may fallback with ordinary < operator on floats.






share|improve this answer

































    2














    Combining the answer from Julien Villemure-Fréchette with the link posted by @alterigel I made my comparison function work:



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


    Please note: This code contains bad style like c-style casts, bad naming and more. My functions and classes are different to the ones posted here. I just stripped everything away to make it easy to understand.



    EDIT:



    I noticed two more mistakes:



    First: It didn't always work for nearly identical vectors.
    Based on @tetorea last comment on my question I changed the function to always get very similar values compared. I use the dot product for that as it is ±1 (or at least close to) for parallel vectors.



    Second: .absolute() was not working because with this function two vectors (-1,1,0) and (1,1,0) were considered parallel which they are clearly not.



    In the code below you can find the corrected version:



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





    share|improve this answer


























    • watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

      – Julien Villemure-Fréchette
      Nov 22 '18 at 21:29











    • @JulienVillemure-Fréchette Thats correct. I will edit my answer.

      – jaba
      Nov 22 '18 at 21:40











    • Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

      – jaba
      Nov 22 '18 at 21:49











    • A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

      – Damien
      Nov 23 '18 at 6:16











    Your Answer






    StackExchange.ifUsing("editor", function () {
    StackExchange.using("externalEditor", function () {
    StackExchange.using("snippets", function () {
    StackExchange.snippets.init();
    });
    });
    }, "code-snippets");

    StackExchange.ready(function() {
    var channelOptions = {
    tags: "".split(" "),
    id: "1"
    };
    initTagRenderer("".split(" "), "".split(" "), channelOptions);

    StackExchange.using("externalEditor", function() {
    // Have to fire editor after snippets, if snippets enabled
    if (StackExchange.settings.snippets.snippetsEnabled) {
    StackExchange.using("snippets", function() {
    createEditor();
    });
    }
    else {
    createEditor();
    }
    });

    function createEditor() {
    StackExchange.prepareEditor({
    heartbeatType: 'answer',
    autoActivateHeartbeat: false,
    convertImagesToLinks: true,
    noModals: true,
    showLowRepImageUploadWarning: true,
    reputationToPostImages: 10,
    bindNavPrevention: true,
    postfix: "",
    imageUploader: {
    brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
    contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
    allowUrls: true
    },
    onDemand: true,
    discardSelector: ".discard-answer"
    ,immediatelyShowMarkdownHelp:true
    });


    }
    });














    draft saved

    draft discarded


















    StackExchange.ready(
    function () {
    StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437344%2fhow-do-i-sort-mathematical-vectors-by-strict-weak-ordering-for-a-map%23new-answer', 'question_page');
    }
    );

    Post as a guest















    Required, but never shown

























    2 Answers
    2






    active

    oldest

    votes








    2 Answers
    2






    active

    oldest

    votes









    active

    oldest

    votes






    active

    oldest

    votes









    7














    It is mathematically impossible to use a tolerance with relational operators and yield a strict weak ordering. Any kind of convergence criterion will fail to satisfy ordering algorithms and data structures requirements. The reason is very simple: the incompatibility of two values, using a tolerance, doesn't yield an equivalence relation since it is not transitive. You may have almostEqual(a, b) and almostEqual(b, c) and yet ~almostEqual(a, c). Try this using a=1.0; b=2.0; c=3.0; tolerance=1.5;. You may look at this answer: Is floating-point == ever OK?.



    You may still define an equivalence relation on floats using truncation, floor, roof, or round kind of functions. Let's define for example less3(a, b) if and only if floor(a * 8) < floor(b * 8) assuming a and b are binary floats and are not NAN and multiplications doesn't yield both the same signed infinite; this compares a and b using 3 bits of precision (0.125 in decimal). Now define equiv3(a, b) if and only if !less3(a, b) && ~less3(b, a). It can be shown that eqiv3(a, b) yields an appropriate equivalence relation. Since less3 is an order relation and equiv3 is an equivalence relation, then less3 is a strict weak order on floats (excluding NANs). Furthermore, in the case a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF you may fallback with ordinary < operator on floats.






    share|improve this answer






























      7














      It is mathematically impossible to use a tolerance with relational operators and yield a strict weak ordering. Any kind of convergence criterion will fail to satisfy ordering algorithms and data structures requirements. The reason is very simple: the incompatibility of two values, using a tolerance, doesn't yield an equivalence relation since it is not transitive. You may have almostEqual(a, b) and almostEqual(b, c) and yet ~almostEqual(a, c). Try this using a=1.0; b=2.0; c=3.0; tolerance=1.5;. You may look at this answer: Is floating-point == ever OK?.



      You may still define an equivalence relation on floats using truncation, floor, roof, or round kind of functions. Let's define for example less3(a, b) if and only if floor(a * 8) < floor(b * 8) assuming a and b are binary floats and are not NAN and multiplications doesn't yield both the same signed infinite; this compares a and b using 3 bits of precision (0.125 in decimal). Now define equiv3(a, b) if and only if !less3(a, b) && ~less3(b, a). It can be shown that eqiv3(a, b) yields an appropriate equivalence relation. Since less3 is an order relation and equiv3 is an equivalence relation, then less3 is a strict weak order on floats (excluding NANs). Furthermore, in the case a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF you may fallback with ordinary < operator on floats.






      share|improve this answer




























        7












        7








        7







        It is mathematically impossible to use a tolerance with relational operators and yield a strict weak ordering. Any kind of convergence criterion will fail to satisfy ordering algorithms and data structures requirements. The reason is very simple: the incompatibility of two values, using a tolerance, doesn't yield an equivalence relation since it is not transitive. You may have almostEqual(a, b) and almostEqual(b, c) and yet ~almostEqual(a, c). Try this using a=1.0; b=2.0; c=3.0; tolerance=1.5;. You may look at this answer: Is floating-point == ever OK?.



        You may still define an equivalence relation on floats using truncation, floor, roof, or round kind of functions. Let's define for example less3(a, b) if and only if floor(a * 8) < floor(b * 8) assuming a and b are binary floats and are not NAN and multiplications doesn't yield both the same signed infinite; this compares a and b using 3 bits of precision (0.125 in decimal). Now define equiv3(a, b) if and only if !less3(a, b) && ~less3(b, a). It can be shown that eqiv3(a, b) yields an appropriate equivalence relation. Since less3 is an order relation and equiv3 is an equivalence relation, then less3 is a strict weak order on floats (excluding NANs). Furthermore, in the case a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF you may fallback with ordinary < operator on floats.






        share|improve this answer















        It is mathematically impossible to use a tolerance with relational operators and yield a strict weak ordering. Any kind of convergence criterion will fail to satisfy ordering algorithms and data structures requirements. The reason is very simple: the incompatibility of two values, using a tolerance, doesn't yield an equivalence relation since it is not transitive. You may have almostEqual(a, b) and almostEqual(b, c) and yet ~almostEqual(a, c). Try this using a=1.0; b=2.0; c=3.0; tolerance=1.5;. You may look at this answer: Is floating-point == ever OK?.



        You may still define an equivalence relation on floats using truncation, floor, roof, or round kind of functions. Let's define for example less3(a, b) if and only if floor(a * 8) < floor(b * 8) assuming a and b are binary floats and are not NAN and multiplications doesn't yield both the same signed infinite; this compares a and b using 3 bits of precision (0.125 in decimal). Now define equiv3(a, b) if and only if !less3(a, b) && ~less3(b, a). It can be shown that eqiv3(a, b) yields an appropriate equivalence relation. Since less3 is an order relation and equiv3 is an equivalence relation, then less3 is a strict weak order on floats (excluding NANs). Furthermore, in the case a * 8 == +INF && b * 8 == +INF || a * 8 == -INF && b * 8 == -INF you may fallback with ordinary < operator on floats.







        share|improve this answer














        share|improve this answer



        share|improve this answer








        edited Nov 22 '18 at 21:01

























        answered Nov 22 '18 at 20:37









        Julien Villemure-FréchetteJulien Villemure-Fréchette

        46528




        46528

























            2














            Combining the answer from Julien Villemure-Fréchette with the link posted by @alterigel I made my comparison function work:



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


            Please note: This code contains bad style like c-style casts, bad naming and more. My functions and classes are different to the ones posted here. I just stripped everything away to make it easy to understand.



            EDIT:



            I noticed two more mistakes:



            First: It didn't always work for nearly identical vectors.
            Based on @tetorea last comment on my question I changed the function to always get very similar values compared. I use the dot product for that as it is ±1 (or at least close to) for parallel vectors.



            Second: .absolute() was not working because with this function two vectors (-1,1,0) and (1,1,0) were considered parallel which they are clearly not.



            In the code below you can find the corrected version:



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





            share|improve this answer


























            • watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

              – Julien Villemure-Fréchette
              Nov 22 '18 at 21:29











            • @JulienVillemure-Fréchette Thats correct. I will edit my answer.

              – jaba
              Nov 22 '18 at 21:40











            • Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

              – jaba
              Nov 22 '18 at 21:49











            • A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

              – Damien
              Nov 23 '18 at 6:16
















            2














            Combining the answer from Julien Villemure-Fréchette with the link posted by @alterigel I made my comparison function work:



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


            Please note: This code contains bad style like c-style casts, bad naming and more. My functions and classes are different to the ones posted here. I just stripped everything away to make it easy to understand.



            EDIT:



            I noticed two more mistakes:



            First: It didn't always work for nearly identical vectors.
            Based on @tetorea last comment on my question I changed the function to always get very similar values compared. I use the dot product for that as it is ±1 (or at least close to) for parallel vectors.



            Second: .absolute() was not working because with this function two vectors (-1,1,0) and (1,1,0) were considered parallel which they are clearly not.



            In the code below you can find the corrected version:



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





            share|improve this answer


























            • watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

              – Julien Villemure-Fréchette
              Nov 22 '18 at 21:29











            • @JulienVillemure-Fréchette Thats correct. I will edit my answer.

              – jaba
              Nov 22 '18 at 21:40











            • Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

              – jaba
              Nov 22 '18 at 21:49











            • A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

              – Damien
              Nov 23 '18 at 6:16














            2












            2








            2







            Combining the answer from Julien Villemure-Fréchette with the link posted by @alterigel I made my comparison function work:



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


            Please note: This code contains bad style like c-style casts, bad naming and more. My functions and classes are different to the ones posted here. I just stripped everything away to make it easy to understand.



            EDIT:



            I noticed two more mistakes:



            First: It didn't always work for nearly identical vectors.
            Based on @tetorea last comment on my question I changed the function to always get very similar values compared. I use the dot product for that as it is ±1 (or at least close to) for parallel vectors.



            Second: .absolute() was not working because with this function two vectors (-1,1,0) and (1,1,0) were considered parallel which they are clearly not.



            In the code below you can find the corrected version:



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





            share|improve this answer















            Combining the answer from Julien Villemure-Fréchette with the link posted by @alterigel I made my comparison function work:



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


            Please note: This code contains bad style like c-style casts, bad naming and more. My functions and classes are different to the ones posted here. I just stripped everything away to make it easy to understand.



            EDIT:



            I noticed two more mistakes:



            First: It didn't always work for nearly identical vectors.
            Based on @tetorea last comment on my question I changed the function to always get very similar values compared. I use the dot product for that as it is ±1 (or at least close to) for parallel vectors.



            Second: .absolute() was not working because with this function two vectors (-1,1,0) and (1,1,0) were considered parallel which they are clearly not.



            In the code below you can find the corrected version:



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






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Nov 26 '18 at 19:01

























            answered Nov 22 '18 at 21:13









            jabajaba

            377215




            377215













            • watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

              – Julien Villemure-Fréchette
              Nov 22 '18 at 21:29











            • @JulienVillemure-Fréchette Thats correct. I will edit my answer.

              – jaba
              Nov 22 '18 at 21:40











            • Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

              – jaba
              Nov 22 '18 at 21:49











            • A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

              – Damien
              Nov 23 '18 at 6:16



















            • watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

              – Julien Villemure-Fréchette
              Nov 22 '18 at 21:29











            • @JulienVillemure-Fréchette Thats correct. I will edit my answer.

              – jaba
              Nov 22 '18 at 21:40











            • Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

              – jaba
              Nov 22 '18 at 21:49











            • A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

              – Damien
              Nov 23 '18 at 6:16

















            watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

            – Julien Villemure-Fréchette
            Nov 22 '18 at 21:29





            watch out for operator precedence, you probably meant to write (int)(lhs.x * prec) instead of (int)lhs.x * prec which is equivalent to floor(lhs.x) * prec

            – Julien Villemure-Fréchette
            Nov 22 '18 at 21:29













            @JulienVillemure-Fréchette Thats correct. I will edit my answer.

            – jaba
            Nov 22 '18 at 21:40





            @JulienVillemure-Fréchette Thats correct. I will edit my answer.

            – jaba
            Nov 22 '18 at 21:40













            Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

            – jaba
            Nov 22 '18 at 21:49





            Another note: While testing int was to small for my values. Either use long, unsigned long long or whatever or even better normalize the vectors if you only care for the direction like me.

            – jaba
            Nov 22 '18 at 21:49













            A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

            – Damien
            Nov 23 '18 at 6:16





            A detail: using unsigned something in such situations is not necessarily a good idea as overflows become much more difficult to detect

            – Damien
            Nov 23 '18 at 6:16


















            draft saved

            draft discarded




















































            Thanks for contributing an answer to Stack Overflow!


            • Please be sure to answer the question. Provide details and share your research!

            But avoid



            • Asking for help, clarification, or responding to other answers.

            • Making statements based on opinion; back them up with references or personal experience.


            To learn more, see our tips on writing great answers.




            draft saved


            draft discarded














            StackExchange.ready(
            function () {
            StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53437344%2fhow-do-i-sort-mathematical-vectors-by-strict-weak-ordering-for-a-map%23new-answer', 'question_page');
            }
            );

            Post as a guest















            Required, but never shown





















































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown

































            Required, but never shown














            Required, but never shown












            Required, but never shown







            Required, but never shown







            這個網誌中的熱門文章

            Tangent Lines Diagram Along Smooth Curve

            Yusuf al-Mu'taman ibn Hud

            Zucchini