So, with the following function in a C program to determine whether a number is prime or composite:
/**
* Determine if a given integer is prime. O(sqrt n).
* n: The integer to examine.
* return: TRUE if n is prime; FALSE if n is not prime.
*/
BOOL APIENTRY IsPrime(int n)
{
int i;
double test;
if(n <= 1) return FALSE;
else if(n <= 3) return TRUE; // Is the else keyword at beginning of this line useful?
for(i = 2; i <= sqrt(n); i++)
{
test = (double) n / (double) i;
if (test == floor(test)) return FALSE;
}
return TRUE;
}
If I replaced line 12 with just if (n <= 3) return TRUE;
the function would still work properly (since the previous if
statement catches the cases where n is not prime on the premise that it is 1, 0 or negative). Should I leave the else
keyword present regardless?
In this situation it's irrelevant since you are returning from the code. In both cases the compiled code will jump to if (n <= 3)
when n > 1
, no matter what.
This because the second condition must be always evaluated if first if
statement is false. This can be easily seen (and should be always verified directly) in the assembler output of both functions:
Ltmp7:
cmpl $2, %edi
jge LBB0_2
xorl %eax, %eax
jmp LBB0_8 // jump to return false
LBB0_2:
movb $1, %r14b
cmpl $4, %edi
jl LBB0_3 // jump to return true
vs
Ltmp15:
cmpl $2, %edi
jge LBB1_2
xorl %eax, %eax
jmp LBB1_8 // jump to return false
LBB1_2:
movb $1, %r14b
cmpl $4, %edi
jl LBB1_3 // jump to return true
An interesting twist is given by modifying the code to something like
if (n <= 3) return n > 1;
because now you have just a branch so it could be optimized differently, for example on my compiler (clang-3.4) it yields
cmpl $4, %edi
jge LBB0_1 // jump to function body
cmpl $1, %edi
setg %al
jmp LBB0_7 // jump to return with $al register already set
which uses the setg
instruction to directly set the return value according to the previous comparison.