-3

So, for the sake of making my code faster, I was hoping to turn my if-statements into ternaries, as this was the perfect place to do so. This is because ternaries are faster than if statements, due to being branchless. Due to how often this line will run, I wanted to optimize it. The original function:

void Union(Node nodes[], Node &n, Node &u)
{
    Node& nRoot = findRoot(nodes, n.val);
    Node& uRoot = findRoot(nodes, u.val);
    int nRootRank = nodes[nRoot.val.second].rank;
    int uRootRank = nodes[uRoot.val.second].rank;

    if (nRootRank < uRootRank) nodes[nRoot.val.second].parent = &uRoot;
    else if (nRootRank > uRootRank) nodes[uRoot.val.second].parent = &nRoot;
    else if (std::rand() % 2)
    {
        nodes[nRoot.val.second].parent = &uRoot;
        uRoot.rank++;
    }
    else
    {
        nodes[uRoot.val.second].parent = &nRoot;
        nRoot.rank++;
    }
}

And the Branchless version:

void Union(Node nodes[], Node &n, Node &u)
{
    Node& nRoot = findRoot(nodes, n.val);
    Node& uRoot = findRoot(nodes, u.val);
    int nRootRank = nodes[nRoot.val.second].rank;
    int uRootRank = nodes[uRoot.val.second].rank;

    (nRootRank < uRootRank) ? nodes[nRoot.val.second].parent = &uRoot : 
    (
        (nRootRank > uRootRank) ? nodes[uRoot.val.second].parent = &nRoot : 
        (
            (std::rand() % 2) ? (nodes[nRoot.val.second].parent = &uRoot, uRoot.rank++) : 
            (
                (nodes[uRoot.val.second].parent = &nRoot, nRoot.rank++) 
            )
        )
    );
}

The problem I run into is that the colon in '(nRootRank > uRootRank) ? nodes[uRoot.val.second].parent = &nRoot : ' says "operand types are incompatible ("Node *" and "int")C/C++(42)" despite that from what I can see, the ternary shouldn't have any problems. Any ideas why it gives that message? And no, for those that go directly to "if is better than ternary" no, it's not, except in the few cases where there's a optimized version hardcoded into c++. If you want info on why, look into banchless programming.

JaMiT
  • 14,422
  • 4
  • 15
  • 31
  • 7
    _" If you want info on why, look into banchless programming."_ You probably misunderstood what this means actually. – πάντα ῥεῖ Jan 01 '21 at 19:42
  • 2
    Something is telling you that using a ternary operator like that is a bad idea. Listen to it. – gnasher729 Jan 01 '21 at 19:44
  • 3
    *This is because ternaries are faster than if statements, due to being branchless.* Uhh.... yeah in general that is a questionable statement, an if/else or ternary may generate the same asssembly code etc, it depends on compiler optimizations. – Borgleader Jan 01 '21 at 19:44
  • 1
    Once you get your code compiling, compare the compiler-generated assembly (with optimizations enabled) between the ternary version and the if-statements version. The results will surprise you. – Sneftel Jan 01 '21 at 19:45
  • Not really, no. In branchless programing you try to remove as many "branches" as possible, as these cause significant slow downs when repeated often. If statements causes a branch to form, ternaries don't. The major exception being the optimizations, as mentioned. – Crimson Twilight Jan 01 '21 at 19:45
  • Also, this has nothing to do with the actual question. – Crimson Twilight Jan 01 '21 at 19:48
  • Look up what value the comma operator returns. (`&uRoot` and `someroot.rank` are not the same type). – 1201ProgramAlarm Jan 01 '21 at 19:49
  • 2
    Just because you can't see the `if` doesn't mean it isn't there. – Retired Ninja Jan 01 '21 at 19:53
  • @1201ProgramAlarm So if I'm understanding you correctly, the problem lies in that I can't set the value of two different value types in a single ternary operation, right? – Crimson Twilight Jan 01 '21 at 19:54
  • 1
    Does this answer your question? [Type error in ternary operator in Eigen](https://stackoverflow.com/questions/43661960/type-error-in-ternary-operator-in-eigen) or possibly [Incompatible operand types when using ternary conditional operator](https://stackoverflow.com/questions/29842095/incompatible-operand-types-when-using-ternary-conditional-operator) – JaMiT Jan 01 '21 at 19:55
  • @RetiredNinja 'if()' is a statement, a ternary is an operator. Yes they function similarly, but they aren't the same thing. – Crimson Twilight Jan 01 '21 at 19:55
  • 1
    You can set different value types, if you're careful. Reverse the operations in the comma operator. Increment first, then do the assignment to `parent` last so that the comma operator returns the same type for all expressions. – 1201ProgramAlarm Jan 01 '21 at 19:56
  • @CrimsonTwilight Those are language constructs. Take a look at the generated code. But you will believe what you will believe. – Retired Ninja Jan 01 '21 at 19:58
  • The Stack Overflow method for indicating that a question is "solved" is to accept an answer, not by editing the title. (There is a 2-day waiting period for accepting your own answer.) – JaMiT Jan 01 '21 at 20:15
  • 1
    @CrimsonTwilight If being a statement and ? being an operator has not much to do with the generated code. The source code describes the semantics of your program against an abstract machine and the compiler can generate *any* code that results in the same observable behavior. This means that it can choose to generate a branch, a conditional move or even optimize out code completely if it can be proven that the behavior does not change. As an example, I created a compilable version of your code in godbolt: https://godbolt.org/z/x7K4M5. See for your self that there is no difference. – Jens Jan 01 '21 at 21:18
  • Ternary operator **is a branch**. Branchless code might be: `bool is_neg = true; int sign = 1 - 2 * is_neg;` instead of `int sign = is_neg ? -1 : 1;` (or the `if` version of that). **You really misunderstand what is branchless!**. – Phil1970 Jan 02 '21 at 01:23

2 Answers2

1

Everyone is quite rightly pointing out that ternary statements ARE branch statements. In the mean time, however, to answer your actual question, your first ternary assigns to a .parent and the last ternary returns the result of .rank++ and that is, indeed, assigning an int to a Node *.

I am slightly curious to find out if a fixed version is faster, but I'm betting it isn't. The only reason it might be is if the optimizer fails, but I have seen weirder ...

Andy Newman
  • 1,178
  • 2
  • 8
  • 23
0

Solved by @1201ProgramAlarm " You can set different value types, if you're careful. Reverse the operations in the comma operator. Increment first, then do the assignment to parent last so that the comma operator returns the same type for all expressions. "