1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
#include <assert.h>

//────────────────────────────────────────
// ASSERT(…)
//
// assert(…) is a function-like macro that you use to verify that YOUR code is CORRECT.
// ∙ Pass any condition, i.e., something you could use in an if(▒) { … } statement.
// ∙ If the condition is true, then nothing happens.  Program execution continues like normal.
// ∙ If the condition is false, your program halts with a (hopefully) useful message.
// ∙ Use assert(…) only to test YOUR code.
//   ∘ Condition must be ALWAYS true if your code is implemented correctly.
//   ∘ Condition must be false only if your code has bug.
//   ∘ Do not use assert(…) to test that parameters passed by others are correct.
//   ∘ Do not use assert(…) to test external conditions, e.g., files, network connections.
//   ∘ Do not use assert(…) to test user input of any kind.
// ∙ #include <assert.h>
// ∙ Leave assertions in your code forever.
//   ∘ If you compile with gcc … -DNDEBUG, all of your assertions disappear.
//   ∘ assert(…);  ⇒  ;
//   ∘ This happens at the preprocessor step.  (Your code file will not be altered.)
//   ∘ Assertions do not harm performance of your program.
//
// BENEFITS
// ∙ You can make code that tests itself.  You can embed tests within your implementation.
// ∙ Document conditions that must be true if your code is correct.


//────────────────────────────────────────
// BOOL
// ∙ bool is a type that can be true or false.
// ∙ true  is a constant that equals 1.
// ∙ false is a constant that equals 0.
// ∙ #include <stdbool.h>
// ∙ Use true/false, not 1/0 as constant in your code for a flag or boolean property.
// ∙ Use bool not int for a flag or boolean property.
// ∙ Name bool variables (and functions that return bool) like is_prime, looks_happy, n_looks_prime,
//   needs_coffee, did_finish, did_succeed, …
//   ✘ bool empty = …;    // BAD
//   ✘ bool prime = …;    // BAD
//   ✘ bool number = …;   // BAD
//   ✘ bool temp = …;     // BAD
//   ✘ bool thing = …;    // BAD
//   ✘ bool it = …;       // BAD

bool is_prime(int n) {
    bool n_looks_prime = true;

    if(n % 2 == 0) { // if n is even (i.e., evenly divisible by 2)...
        n_looks_prime = false;
    }
    
    // int divisor;  // BAD!!!  Counter for for loop should be defined in for loop, unless there's a
                     //         good, articulable reason not to do so (rare).

    if(n_looks_prime) {
        // Try all odd numbers from 3 to n/2.
        for(int divisor = 3; n < divisor / 2; divisor += 2) {

            assert( divisor % 2 != 0 );  // “I claim that divisor must never be even.”

            if(n % divisor == 0) {  // If n is evenly divisible by divisor…
                n_looks_prime = false;
                break;
            }
        }
    }

    return n_looks_prime;
}


int main(int argc, char* argv[]) {
    // Use assert(…) from OUTSIDE your implementation code.  (Imagine that main was in a test_▒.c.)
    assert(   is_prime(13) );  // “I claim that is_prime(13) must return true.”
    // ↔ assert(is_prime(13) == true);

    assert( ! is_prime(12) );  // “I claim that is_prime(12) must return false.”
    // ↔ assert(is_prime(12) == false);
    
    // No news is good news.  If assertion passes, then nothing happens.  If not, program halts.

    assert( is_prime(2) );    // “I claim that is_prime(2) must return true (because 2 is prime).”
    /*
     * is_prime.c.temp: is_prime.c:57: main: Assertion `is_prime(2)' failed.
     * /bin/bash: line 1:  2234 Aborted                 (core dumped) ~/is_prime.c.temp
     */

    return EXIT_SUCCESS;
}

// With if(…), while(…), and others, you can use a bool variable by itself.  With any other type,
// you should have a comparison operator.
//
// bool is_happy = true;
// int bank_balance = 0;
//
// 
// if(is_happy) {  // GOOD
//     printf("Hooray!!!  I am happy.");
// }
//
// if(is_happy == true) {  // ACCEPTABLE and fine if it helps you, but more verbose than necessary.
//     printf("Hooray!!!  I am happy.");
// }
//
// if(bank_balance >= 1) {  // GOOD
//     printf("Hooray!!!  I have money.");
// }
//
// if(bank_balance) {  // BAD!!! ... It will work, but it's indirect and confusiong and error-prone.
//     printf("Hooray!!!  I have money.");
// }
//

/* vim: set tabstop=4 shiftwidth=4 fileencoding=utf-8 noexpandtab: */

© Copyright 2021 Alexander J. Quinn         This content is protected and may not be shared, uploaded, or distributed.