Search code examples
cif-statementreturncontrol-flow

Is the 'else if' redundant in this function?


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?


Solution

  • 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.