CS1010 Notes
  • Welcome
  • Lec/Tut/Lab/Exes
    • Lecture
      • Lec 01 - Computational Problem Solving
      • Lec 02 - Functions and Types
      • Lec 03 - Basic C Programming
      • Lec 04 - Conditionals
      • Lec 05 - Loops
      • Lec 06 - Call Stacks, Arrays
        • Diagnostic Quiz
      • Lec 07 - Pointers, Memory management
        • Diagnostic Quiz
      • Lec 08 - Multi-d Array, Efficiency
        • Diagnostic Quiz
      • Lec 09 - Searching and Sorting
        • Diagnostic Quiz
      • Lec 10 - More Recursion
        • Diagnostic Quiz
      • Lec 11 - Strcut & Standard I/O
        • Diagnostic Quiz
      • Lec 12 - Recap
    • Tutorial
      • Tut 01 - Computational Problem-Solving
      • Tut 02 - Functions and Conditionals
      • Tut 03 - More on Conditionals
      • Tut 04 - Loops
      • Tut 08 - Searching and Sorting
    • Lab
      • Lab 01 - Unix/Vim Setup
      • Lab 02 - Debugging
      • Lab 03 - Assert
      • Lab 04 - Test Cases
      • Lab 05 - Arrays
      • Lab 06 - Memory Errors
      • Lab 07 - Compiling with Clang
      • Lab 08 - C Preprocessor
      • Lab 09 - Backtracking
      • Lab 10 - Struct and Wrap up
    • Exercises
      • Exercise 3 - Fixed-Length Arrays
      • Exercise 4 - Dynamic Arrays and Strings
      • Exercise 6 - Searching and Sorting
      • Exercise 7 - More Recursion
      • Exercise 8 - Struct
  • Past Year Exam
    • Midterm PE
      • PE1 (AY18/19)
      • PE1 (AY20/21)
      • PE1 (AY21/22)
      • PE0 (AY22/23)
      • PE0 (AY23/24)
    • Midterm Paper
      • Midterm (AY18/19)
      • Midterm (AY20/21)
      • Midterm (AY21/22)
      • Midterm (AY22/23)
    • PE1 Review
      • PE1 (AY23/24)
    • PE2 Review
      • PE2 (AY18/19)
      • PE2 (AY20/21)
      • PE2 (AY21/22)
      • PE2 (AY22/23)
      • PE2 (AY23/24)
    • Final Paper
      • Final (AY18/19)
      • Final (AY20/21)
      • Final (AY21/22)
      • Final (AY22/23)
      • Final (AY23/24)
  • Current Year Exam
    • PE0 (AY24/25)
    • PE1 (AY24/25)
    • PE2 (AY24/25)
    • Final (AY24/25)
  • Toolbox
    • Vim & Unix
    • GDB
  • After CS1010
Powered by GitBook
On this page
  • Testing
  • Some conventions
  • Test Case Design
  • Example
  • Exercise 2 Review
  • factor.c
  • collatz.c
  • pattern.c
  • A Little Extension on prime.c
  • Question
  • Naive Solution
  • Optimized Solution
Edit on GitHub
  1. Lec/Tut/Lab/Exes
  2. Lab

Lab 04 - Test Cases

Thanks for my Lab Tutor Zhang Puyu

PreviousLab 03 - AssertNextLab 05 - Arrays

Last updated 6 months ago

Slides:

Testing

Some conventions

  1. It is impossible to enumerate all test cases.

  2. It is possible to divide the test cases into a few groups.

  3. We can choose to test for all possible classes of inputs/outputs.

  4. Test for the boundary cases according to the constraints given.

Test Case Design

  • Should cover all conditional (i.e. for all conditional branch, there exists at least one test case which can enter that branch)

  • Should contain at least one case for 0 iteration and at least one case for k iterations where k≥1k\geq1k≥1.

  • Should contain boundary conditions.

Example

Design the test cases for the program below:

long find_least_significant_9(long n) {
    long count = 1;
    while (n != 0) {
        if ((n % 10) == 9) {
            return count;
        }
        n /= 10;
        count += 1;
    }
    return 0;
}
  1. We won't enter the loop while n != 0, that means n=0n=0n=0 and now our output is 0, which is correct.

  2. We enter the loop, which means n≠0n\neq0n=0.

    1. We don't enter the conditonal first. So, that means there is no 9 in n

    2. We enter the conditional, which means there is at leasat a 9 in n

      1. 9 in the last digit.

      2. 9 in the middle.

      3. Have multiple 9.

Testing Tips:

  1. Test each function seperately (print out the value to be returned and compare it with your expectation!

  2. Decompose your program into shorter and simpler functions: simpler code is easier to test!

Exercise 2 Review

factor.c

Optimization methods:

  1. n−1→n2n-1\rightarrow \frac{n}{2}n−1→2n​ since anything bigger than n2\frac{n}{2}2n​ for sure cannot divide nnn!

  2. If iii divides nnn, then surely ni\frac{n}{i}in​ divides nnn as well. See Proof of 2.

The above implies that we can count factors in pairs.

Note that if iii divides nnn and i<ni<\sqrt{n}i<n​, then ni>n\frac{n}{i}>\sqrt{n}in​>n​

So, the supremum (the least upper bound) is n\sqrt{n}n​.

We should then deal with the special case where nnn is a perfect square (a perfet square has an odd numbero factors while any other integer has an even number of factors)

Proof of 2.

If iii divides nnn, then we can write n=qin=qin=qi, where q≠0q\neq0q=0. Manipulate this equation, we know q=niq=\frac{n}{i}q=in​. So, now our problem becomes does qqq divide nnn right? This answer is obvious yes right, since we already know that n=qin=qin=qi. Proof!

collatz.c

When to use for or while?

`for` is used under the circumstances where we iterate through consecutive numbers. `while` loops are used under the circumstances that we don't iterate through consecutive numbers, which means that we can define a more general condition to "loop through".

pattern.c

A Little Extension on prime.c

Question

How to find all primes less than or equal to nnn.

Naive Solution

We iterate every integer from nnn to 222 (even if we exclude all even numbers, there are still n2\frac{n}{2}2n​ steps. And checking if each integer is prime takes another n\sqrt{n}n​ steps in the worst case, so in total there are about nn2\frac{n\sqrt{n}}{2}2nn​​ steps -- Slow!

Optimized Solution

Using an array, we can speed up the algorithm. The algorithm we are using is called Sieve of Eratosthenes.

Consider all integers from 222 to nnn

2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,...,n2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,...,n2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,...,n

Take 2 (which happens to be the smallest prime), and cross out all multiples of 2 in the list.

Take the un-crossed integer (which is 3 in this case), and cross out all muptiples of 3.

Iterate through the list while repeating the above process. We claim that: each time we come across an un-crossed integer iii, it will be a prime.

Why?

Let's use proof by contracdiction. If it is not a prime, the it must have factors smaller than it. However, during our "cross-out" procedure, all the multiple of the number smaller than it must be crossed out. So, that means this number has been crossed out. Contradiction! So, that means this number we encounter is prime.

Stop when we encounter the first integer that is bigger than n\sqrt{n}n​. We claim that from this integer onwards, all un-crossed integers are prime!

Why?

Use proof by contracdiction also. If this number (n) is not a prime. That means n has factors that are not itself and 1. And one of its factor must be smaller than or equal to its square root. However, we have crossed out all the numbers that are multiple of that square root since it's smaller the n. So, this means this number is already crossed out. Contradiction!

Number of operations in the worst case: upper-bounded by nlog(log(n))nlog(log(n))nlog(log(n)) (fewer than nnn\sqrt{n}nn​).

Proof

The proof is far beyond the scope of this course and contains much mathematical knowledge. I haven't digged deep into it but below are some useful resources:

(Page 30)

https://en.wikipedia.org/wiki/Divergence_of_the_sum_of_the_reciprocals_of_the_primes#Proof_that_the_series_exhibits_log-log_growth
https://github.com/Z-Puyu/lecture-notes/blob/MA2214-Combinatorics-and-Graphs-I/Combinatorics%20and%20Graphs%20I.pdf
102KB
Lab4.pdf
pdf
Lab 4 Slides