Which is the fastest way to get the absolute value of a number

后端 未结 14 799
陌清茗
陌清茗 2020-12-07 19:10

Which is the fastest way to implement an operation that returns the absolute value of a number?

x=root(x²)

or

if !isPositiv         


        
相关标签:
14条回答
  • 2020-12-07 19:16

    There is a great trick to calculate the absolute value of a 2s-complement integer without using an if statement. The theory goes, if the value is negative you want to toggle the bits and add one, otherwise you want to pass the bits through as is. A XOR 1 happens to toggle A and A XOR 0 happens to leave A intact. So you want do something like this:

      uint32_t temp = value >> 31;     // make a mask of the sign bit
      value ^= temp;                   // toggle the bits if value is negative
      value += temp & 1;               // add one if value was negative
    

    In principle, you can do it in as few as three assembly instructions (without a branch). And you'd like to think that the abs() function that you get with math.h does it optimally.

    No branches == better performance. Contrary to @paxdiablo's response above, this really matters in deep pipelines where the more branches you have in your code, the more likely you are to have your branch predictor get it wrong and have to roll-back, etc. If you avoid branching where possible, things will keep moving along at full throttle in your core :).

    0 讨论(0)
  • 2020-12-07 19:16

    Calculating the square root is probably one of the worst things you could do because it is really slow. Usually there is a library function for doing this; something like Math.Abs(). Multiplying with -1 is also unnecessary; just return -x. So a good solution would be the following.

    (x >= 0) ? x : -x
    

    The compiler will probably optimize this to a single instructions. Conditions may be quite expensive on modern processors because of the long execution pipelines -the calculations must be thrown away if a branch was misspredicted and the processor started executing the instructions from the wrong code path. But because of the mentioned compiler optimization you need not care in this case.

    0 讨论(0)
  • 2020-12-07 19:18

    The time taken to do a square root is much greater than the time taken to do an conditional. If you have been taught to avoid conditionals because they are slow, then you have been misinformed. They are a good deal slower than trivial operations like adding or subtracting integers or bit shifting - which is why unrolling loops can be of benefit only if you are doing such trivial operations. But in the grand scheme of things conditionals are good and fast, not bad and slow. To do something as complicated as call a function or calculate a square root to avoid a conditional statement is crazy.

    Also, instead of (x = x * -1) why not do (x = 0 - x)? Maybe the compiler will optimize them the same, but isn't the second one simpler anyway?

    0 讨论(0)
  • 2020-12-07 19:19

    Are you using 8086 assembly? ;-)

                    ; abs value of AX
       cwd          ; replicate the high bit into DX
       xor  ax, dx  ; take 1's complement if negative; no change if positive
       sub  ax, dx  ; AX is 2's complement if it was negative The standard
                    : absolute value method works on any register but is much
                    ; slower:
    
       or   bx, bx  ; see if number is negative
       jge  notneg  ; if it is negative...
       neg  bx      ; ...make it positive
    notneg:         ; jump to here if positive
    

    (flagrantly stolen)

    0 讨论(0)
  • 2020-12-07 19:20

    Conditionals are slower than plain arithmetic operations, but much, much faster than something as silly as calculating the square root.

    Rules of thumb from my assembly days:

    • Integer or bitwise op: 1 cycle
    • Floating-point add/sub/mul: 4 cycles
    • Floating-point div: ~30 cycles
    • Floating-point exponentiation: ~200 cycles
    • Floating-point sqrt: ~60 cycles depending on implementation
    • Conditional branch: avg. 10 cycles, better if well-predicted, much worse if mispredicted
    0 讨论(0)
  • 2020-12-07 19:21

    I'm doing some retro graphics programming in C for 8088/8086 and calling abs() is time consuming so I've replaced it with:

    /* assuming 'i' is int; this WILL NOT WORK on floating point */
    if (i < 0) {
        i = ~i + 1;
    }
    

    The reason this is faster is because it essentially trades a CALL in assembly for a JNE. Calling a method changes a couple of registers, pushes several more, pushes arguments onto the stack, and can flush the prefetch queue. Plus these actions need to be reversed at the end of the function and all of this is very expensive to the CPU.

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