Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the most efficient way to detect even numbers in Java? [duplicate]

What would be the most efficient manner to determine that a number is even using Java, and why?

Would it be using modulo or subtraction, or some other manner that I haven't actually thought of?

One imagines I could determine this doing a simple test class - and I can - but that really wouldn't explain why, would it?

I'm not doing some crazy-pants performance tuning for some lofty goal of processing that many items faster. But I was curious if one method should be preferred over the other as common practice. In the same way we wouldn't use & in place of &&, why use % when we can use &?

like image 583
bharal Avatar asked Jun 06 '13 18:06

bharal


People also ask

How do you check if a number is even in Java?

If a number is evenly divisible by 2 with no remainder, then it is even. You can calculate the remainder with the modulo operator % like this num % 2 == 0 . If a number divided by 2 leaves a remainder of 1, then the number is odd. You can check for this using num % 2 == 1 .

What is the easiest way to determine if a number is odd or even?

To tell whether a number is even or odd, look at the number in the ones place. That single number will tell you whether the entire number is odd or even. An even number ends in 0, 2, 4, 6, or 8. An odd number ends in 1, 3, 5, 7, or 9.


1 Answers

If you check the assembly generated by hotspot 7 of these two methods:

public static boolean isEvenBit(int i) {
    return (i & 1) == 0;
}
public static boolean isEvenMod(int i) {
    return i % 2 == 0;
}

you will see that although the mod is optimised and basically does a bitwise and but it has a few extra instructions because the two operations are not strictly equivalent*. Other JVMs might optimise it differently. The assembly is posted below for reference.

I also ran a micro benchmark which confirms our observation: isEventBit is marginally faster (but both run in about 2 nanoseconds so probably won't have much of an inmpact on a typical program as a whole):

Benchmark                     Mode  Samples  Score   Error  Units
c.a.p.SO16969220.isEvenBit    avgt       10  1.869 ± 0.069  ns/op
c.a.p.SO16969220.isEvenMod    avgt       10  2.554 ± 0.142  ns/op

isEvenBit

  # {method} 'isEvenBit' '(I)Z' in 'javaapplication4/Test1'
  # parm0:    rdx       = int
  #           [sp+0x20]  (sp of caller)
  0x00000000026c2580: sub    rsp,0x18
  0x00000000026c2587: mov    QWORD PTR [rsp+0x10],rbp  ;*synchronization entry
                                                ; - javaapplication4.Test1::isEvenBit@-1 (line 66)
  0x00000000026c258c: and    edx,0x1
  0x00000000026c258f: mov    eax,edx
  0x00000000026c2591: xor    eax,0x1            ;*ireturn
                                                ; - javaapplication4.Test1::isEvenBit@11 (line 66)
  0x00000000026c2594: add    rsp,0x10
  0x00000000026c2598: pop    rbp
  0x00000000026c2599: test   DWORD PTR [rip+0xfffffffffdb6da61],eax        # 0x0000000000230000
                                                ;   {poll_return}
  0x00000000026c259f: ret    

isEvenMod

  # {method} 'isEvenMod' '(I)Z' in 'javaapplication4/Test1'
  # parm0:    rdx       = int
  #           [sp+0x20]  (sp of caller)
  0x00000000026c2780: sub    rsp,0x18
  0x00000000026c2787: mov    QWORD PTR [rsp+0x10],rbp  ;*synchronization entry
                                                ; - javaapplication4.Test1::isEvenMod@-1 (line 63)
  0x00000000026c278c: mov    r10d,edx
  0x00000000026c278f: and    r10d,0x1           ;*irem
                                                ; - javaapplication4.Test1::isEvenMod@2 (line 63)
  0x00000000026c2793: mov    r11d,r10d
  0x00000000026c2796: neg    r11d
  0x00000000026c2799: test   edx,edx
  0x00000000026c279b: cmovl  r10d,r11d
  0x00000000026c279f: test   r10d,r10d
  0x00000000026c27a2: setne  al
  0x00000000026c27a5: movzx  eax,al
  0x00000000026c27a8: xor    eax,0x1            ;*ireturn
                                                ; - javaapplication4.Test1::isEvenMod@11 (line 63)
  0x00000000026c27ab: add    rsp,0x10
  0x00000000026c27af: pop    rbp
  0x00000000026c27b0: test   DWORD PTR [rip+0xfffffffffdb6d84a],eax        # 0x0000000000230000
                                                ;   {poll_return}
  0x00000000026c27b6: ret    

* as pointed out in the comments, % isn't really modulo; it's the remainder. So (i % 2) != (i & 1) if i < 0. The extra instructions in the isEvenMod code sets the sign of the result to the sign of i (and then just compares it to zero, so the effort is wasted).

like image 109
assylias Avatar answered Nov 07 '22 01:11

assylias