Is < faster than <=?

后端 未结 14 841
孤城傲影
孤城傲影 2020-11-22 13:43

Is if( a < 901 ) faster than if( a <= 900 ).

Not exactly as in this simple example, but there are slight performance changes on loop

相关标签:
14条回答
  • 2020-11-22 14:07

    TL;DR answer

    For most combinations of architecture, compiler and language, < will not be faster than <=.

    Full answer

    Other answers have concentrated on x86 architecture, and I don't know the ARM architecture (which your example assembler seems to be) well enough to comment specifically on the code generated, but this is an example of a micro-optimisation which is very architecture specific, and is as likely to be an anti-optimisation as it is to be an optimisation.

    As such, I would suggest that this sort of micro-optimisation is an example of cargo cult programming rather than best software engineering practice.

    Counterexample

    There are probably some architectures where this is an optimisation, but I know of at least one architecture where the opposite may be true. The venerable Transputer architecture only had machine code instructions for equal to and greater than or equal to, so all comparisons had to be built from these primitives.

    Even then, in almost all cases, the compiler could order the evaluation instructions in such a way that in practice, no comparison had any advantage over any other. Worst case though, it might need to add a reverse instruction (REV) to swap the top two items on the operand stack. This was a single byte instruction which took a single cycle to run, so had the smallest overhead possible.

    Summary

    Whether or not a micro-optimisation like this is an optimisation or an anti-optimisation depends on the specific architecture you are using, so it is usually a bad idea to get into the habit of using architecture specific micro-optimisations, otherwise you might instinctively use one when it is inappropriate to do so, and it looks like this is exactly what the book you are reading is advocating.

    0 讨论(0)
  • 2020-11-22 14:10

    Only if the people who created the computers are bad with boolean logic. Which they shouldn't be.

    Every comparison (>= <= > <) can be done in the same speed.

    What every comparison is, is just a subtraction (the difference) and seeing if it's positive/negative.
    (If the msb is set, the number is negative)

    How to check a >= b? Sub a-b >= 0 Check if a-b is positive.
    How to check a <= b? Sub 0 <= b-a Check if b-a is positive.
    How to check a < b? Sub a-b < 0 Check if a-b is negative.
    How to check a > b? Sub 0 > b-a Check if b-a is negative.

    Simply put, the computer can just do this underneath the hood for the given op:

    a >= b == msb(a-b)==0
    a <= b == msb(b-a)==0
    a > b == msb(b-a)==1
    a < b == msb(a-b)==1

    and of course the computer wouldn't actually need to do the ==0 or ==1 either.
    for the ==0 it could just invert the msb from the circuit.

    Anyway, they most certainly wouldn't have made a >= b be calculated as a>b || a==b lol

    0 讨论(0)
  • 2020-11-22 14:12

    Historically (we're talking the 1980s and early 1990s), there were some architectures in which this was true. The root issue is that integer comparison is inherently implemented via integer subtractions. This gives rise to the following cases.

    Comparison     Subtraction
    ----------     -----------
    A < B      --> A - B < 0
    A = B      --> A - B = 0
    A > B      --> A - B > 0
    

    Now, when A < B the subtraction has to borrow a high-bit for the subtraction to be correct, just like you carry and borrow when adding and subtracting by hand. This "borrowed" bit was usually referred to as the carry bit and would be testable by a branch instruction. A second bit called the zero bit would be set if the subtraction were identically zero which implied equality.

    There were usually at least two conditional branch instructions, one to branch on the carry bit and one on the zero bit.

    Now, to get at the heart of the matter, let's expand the previous table to include the carry and zero bit results.

    Comparison     Subtraction  Carry Bit  Zero Bit
    ----------     -----------  ---------  --------
    A < B      --> A - B < 0    0          0
    A = B      --> A - B = 0    1          1
    A > B      --> A - B > 0    1          0
    

    So, implementing a branch for A < B can be done in one instruction, because the carry bit is clear only in this case, , that is,

    ;; Implementation of "if (A < B) goto address;"
    cmp  A, B          ;; compare A to B
    bcz  address       ;; Branch if Carry is Zero to the new address
    

    But, if we want to do a less-than-or-equal comparison, we need to do an additional check of the zero flag to catch the case of equality.

    ;; Implementation of "if (A <= B) goto address;"
    cmp A, B           ;; compare A to B
    bcz address        ;; branch if A < B
    bzs address        ;; also, Branch if the Zero bit is Set
    

    So, on some machines, using a "less than" comparison might save one machine instruction. This was relevant in the era of sub-megahertz processor speed and 1:1 CPU-to-memory speed ratios, but it is almost totally irrelevant today.

    0 讨论(0)
  • 2020-11-22 14:13

    I see that neither is faster. The compiler generates the same machine code in each condition with a different value.

    if(a < 901)
    cmpl  $900, -4(%rbp)
    jg .L2
    
    if(a <=901)
    cmpl  $901, -4(%rbp)
    jg .L3
    

    My example if is from GCC on x86_64 platform on Linux.

    Compiler writers are pretty smart people, and they think of these things and many others most of us take for granted.

    I noticed that if it is not a constant, then the same machine code is generated in either case.

    int b;
    if(a < b)
    cmpl  -4(%rbp), %eax
    jge   .L2
    
    if(a <=b)
    cmpl  -4(%rbp), %eax
    jg .L3
    
    0 讨论(0)
  • 2020-11-22 14:13

    Maybe the author of that unnamed book has read that a > 0 runs faster than a >= 1 and thinks that is true universally.

    But it is because a 0 is involved (because CMP can, depending on the architecture, replaced e.g. with OR) and not because of the <.

    0 讨论(0)
  • 2020-11-22 14:14

    At the very least, if this were true a compiler could trivially optimise a <= b to !(a > b), and so even if the comparison itself were actually slower, with all but the most naive compiler you would not notice a difference.

    0 讨论(0)
提交回复
热议问题