I wanted to confirm that the modulo operation was an expensive operation so I tested this piece of code that checks if a given number is even:
bool is_even(int n) {
return (n & 1) == 0;
}
then this one:
bool is_even_bis(int n) {
return (n % 2) == 0;
}
I used C# at first and indeed, the code using logical &
is faster than the other one, sometimes even three times faster. Using ILSpy I saw that there was no optimization done when compiled to MSIL, the code is strictly the same.
However as spotted by a friend of mine in C, using gcc -O3
the code is compiled to:
is_even:
mov eax, DWORD PTR [esp+4] # tmp63, n
and eax, 1 # tmp63,
xor eax, 1 # tmp63,
ret
and:
is_even_bis:
mov eax, DWORD PTR [esp+4] # tmp63, n
and eax, 1 # tmp63,
xor eax, 1 # tmp63,
ret
So basically strictly the same thing. Even when using -O0
optimization the operation doesn't even appear:
is_even:
push ebp #
mov ebp, esp #,
mov eax, DWORD PTR [ebp+8] # tmp63, n
and eax, 1 # D.1837,
test eax, eax # D.1837
sete al #, D.1838
movzx eax, al # D.1836, D.1838
pop ebp #
ret
Needlessly to say the compiled code is the same between is_even
and is_even_bis
in -O0
as well.
Even more funny if I may say, another friend of mine tried the same using OCaml:
let is_even x = ((x land 1) == 0)
let _ =
let i = ref 100000000 in
while !i > 0 do
ignore (is_even !i);
decr i
done
and:
let is_even_bis x = ((x mod 2) == 0)
let _ =
let i = ref 100000000 in
while !i > 0 do
ignore (is_even_bis !i);
decr i
done
And it appears that the modulo version is faster when running the bytecode but slower in native code! Maybe someone can explain this mystery?
Then I started wondering why it does not behave like that in C# (where there is an obvious gap of performance between the two functions) and why the JIT compiler does not apply the same optimization as gcc
. I don't know if there's a way to intercept the output of the JIT compiler, maybe that would help to understand?
Bonus question : I guess the modulo is based on division and since the division is done in O(n²) time (n being the number of digits) can we say that the modulo has quadratic time complexity?