1 Question I – Paper Folding vs Mount Everest

1.1 Problem Statement

A piece of paper is 1 mm thick. Assuming you can fold it as many times as you want, how many folds would it take to exceed the height of Mount Everest at 8,848 m?

1.2 Mathematical Reasoning

Each fold doubles the thickness. After \(n\) folds:

\[\text{thickness} = 1\,\text{mm} \times 2^n\]

We need:

\[2^n > 8{,}848{,}000\,\text{mm} \implies n > \log_2(8{,}848{,}000) \approx 23.08 \implies n = 24\]

1.3 R Solution

# =============================================================
# Question I: Paper Folding vs Mount Everest
# =============================================================

paper_thickness_mm <- 1               # Initial thickness in mm
everest_height_mm  <- 8848 * 1000     # Everest height converted to mm

thickness <- paper_thickness_mm
folds     <- 0                        # Fold counter

# Each fold doubles the thickness; loop until we exceed Everest
while (thickness <= everest_height_mm) {
  thickness <- thickness * 2          # Double the thickness
  folds     <- folds + 1              # Increment fold counter
}

cat("=============================================\n")
#> =============================================
cat("       Paper Folding vs Mount Everest\n")
#>        Paper Folding vs Mount Everest
cat("=============================================\n")
#> =============================================
cat("Number of folds required :", folds, "\n")
#> Number of folds required : 24
cat("Resulting thickness      :", round(thickness / 1e6, 3), "km\n")
#> Resulting thickness      : 16.777 km
cat("Mount Everest height     :", everest_height_mm / 1e6,   "km\n")
#> Mount Everest height     : 8.848 km
cat("Exceeds Everest by       :", round((thickness - everest_height_mm) / 1e6, 3), "km\n")
#> Exceeds Everest by       : 7.929 km

1.4 Visualisation – Thickness Growth per Fold

# Build a data frame tracking thickness at every fold
fold_seq  <- 0:folds
thickness_seq <- paper_thickness_mm * 2^fold_seq   # vectorised doubling

df <- data.frame(
  Fold      = fold_seq,
  Thickness = thickness_seq / 1e6   # convert mm to km
)

# Base-R plot
plot(
  df$Fold, df$Thickness,
  type = "b", pch = 16, col = "#2E5FA3",
  xlab = "Number of Folds",
  ylab = "Thickness (km)",
  main = "Paper Thickness After Each Fold",
  log  = "y"   # log scale to show exponential growth clearly
)
abline(h = 8.848, col = "red", lty = 2, lwd = 2)
legend("topleft",
       legend = c("Paper thickness", "Everest (8.848 km)"),
       col    = c("#2E5FA3", "red"),
       lty    = c(1, 2), pch = c(16, NA))


2 Question II – Sum & Average of Odd Integers

2.1 Problem Statement

Write an R program that reads a set of numbers, stores them in a list, and computes the sum and average of all odd integers. Input ends when the user enters -1. The program must:

  • Store all inputs but ignore duplicates
  • Ignore non-integer and negative values during computation

2.2 R Solution

Note: readline() works interactively. The chunk below uses a hardcoded demo vector to show the logic; replace demo_inputs with real readline() input when running interactively.

# =============================================================
# Question II: Sum & Average of Odd Integers
# =============================================================

# ── Demo inputs (replace with readline() loop interactively) ──
# Simulates the user typing: 7, 3, hello, 7, -4, 12, 9, 3.5, -1
demo_inputs <- c(7, 3, NA, 7, -4, 12, 9, 3.5)
# NA above represents the rejected non-numeric "hello"

all_inputs <- c()   # Will hold every unique valid entry

for (num in demo_inputs) {

  # Skip non-numeric values (NA from failed as.numeric conversion)
  if (is.na(num)) {
    cat("  [!] Non-numeric value ignored.\n")
    next
  }

  # Reject duplicates
  if (num %in% all_inputs) {
    cat("  [!] Duplicate", num, "ignored.\n")
    next
  }

  # Store the value (negatives stored but excluded from computation)
  all_inputs <- c(all_inputs, num)
  cat("  [+] Stored:", num, "\n")
}
#>   [+] Stored: 7 
#>   [+] Stored: 3 
#>   [!] Non-numeric value ignored.
#>   [!] Duplicate 7 ignored.
#>   [+] Stored: -4 
#>   [+] Stored: 12 
#>   [+] Stored: 9 
#>   [+] Stored: 3.5
# ── Computations ──────────────────────────────────────────────
# Only non-negative whole integers qualify
non_neg_integers <- all_inputs[all_inputs >= 0 & floor(all_inputs) == all_inputs]

# Odd: remainder when divided by 2 equals 1
odd_integers <- non_neg_integers[non_neg_integers %% 2 != 0]

# ── Results ───────────────────────────────────────────────────
cat("\n=============================================\n")
#> 
#> =============================================
cat("All stored inputs :", toString(all_inputs), "\n")
#> All stored inputs : 7, 3, -4, 12, 9, 3.5
cat("Non-neg integers  :", toString(non_neg_integers), "\n")
#> Non-neg integers  : 7, 3, 12, 9
cat("Odd integers found:", toString(odd_integers), "\n")
#> Odd integers found: 7, 3, 9
if (length(odd_integers) == 0) {
  cat("No odd non-negative integers were entered.\n")
} else {
  cat("Sum of odd integers    :", sum(odd_integers),  "\n")
  cat("Average of odd integers:", mean(odd_integers), "\n")
}
#> Sum of odd integers    : 19 
#> Average of odd integers: 6.333333

2.3 Interactive Version (run outside of knit)

# ── Interactive loop (eval=FALSE so it doesn't block knitting) ──
all_inputs <- c()

cat("Enter numbers one at a time. Enter -1 to quit.\n")

repeat {
  raw <- readline(prompt = "Number: ")
  num <- suppressWarnings(as.numeric(raw))

  if (is.na(num))       { cat("  [!] Non-numeric – ignored.\n"); next }
  if (num == -1)          break
  if (num %in% all_inputs){ cat("  [!] Duplicate – ignored.\n");  next }

  all_inputs <- c(all_inputs, num)
  cat("  [+] Stored:", num, "\n")
}

non_neg_integers <- all_inputs[all_inputs >= 0 & floor(all_inputs) == all_inputs]
odd_integers     <- non_neg_integers[non_neg_integers %% 2 != 0]

cat("Sum    :", sum(odd_integers),  "\n")
cat("Average:", mean(odd_integers), "\n")

3 Question III – Comma-Separated Number Analysis

3.1 Problem Statement

Accept a sequence of comma-separated numbers and:

  1. Generate and display a list and a tuple
  2. Display all pairs of numbers
  3. Print both in sorted ascending order
  4. Display min and max
  5. Display sum and average

3.2 R Solution

# =============================================================
# Question III: Comma-Separated Number Analysis
# Note: R has no native tuple type. A numeric vector is used
#       by convention to simulate Python's immutable tuple.
# =============================================================

# ── Demo input (replace readline() when running interactively) ─
raw_input <- "10,13,17,20,14"
cat("Input:", raw_input, "\n\n")
#> Input: 10,13,17,20,14
# Split on commas, trim whitespace, convert to numeric
tokens  <- strsplit(raw_input, ",")[[1]]
numbers <- as.numeric(trimws(tokens))

# Remove any values that failed conversion
if (any(is.na(numbers))) {
  cat("[!] Non-numeric tokens removed.\n")
  numbers <- numbers[!is.na(numbers)]
}

# ── List and Tuple ────────────────────────────────────────────
num_list  <- as.list(numbers)   # R list  ~ Python list
num_tuple <- numbers            # numeric vector ~ Python tuple

cat("List  :", paste0("[", paste(numbers,    collapse = ", "), "]"), "\n")
#> List  : [10, 13, 17, 20, 14]
cat("Tuple :", paste0("(", paste(num_tuple,  collapse = ", "), ")"), "\n")
#> Tuple : (10, 13, 17, 20, 14)
# ── All Unique Pairs ──────────────────────────────────────────
# combn() produces every size-2 combination without repetition
pairs     <- combn(numbers, 2, simplify = FALSE)
pair_strs <- sapply(pairs, function(p) paste0("{", p[1], ", ", p[2], "}"))

cat("\nPairs:\n")
#> 
#> Pairs:
cat(" ", paste(pair_strs, collapse = ", "), "\n")
#>   {10, 13}, {10, 17}, {10, 20}, {10, 14}, {13, 17}, {13, 20}, {13, 14}, {17, 20}, {17, 14}, {20, 14}
# ── Sorted Versions ───────────────────────────────────────────
sorted_vec <- sort(numbers)   # ascending order (default)

cat("\nSorted List  :", paste0("[", paste(sorted_vec, collapse = ", "), "]"), "\n")
#> 
#> Sorted List  : [10, 13, 14, 17, 20]
cat("Sorted Tuple :", paste0("(", paste(sorted_vec, collapse = ", "), ")"), "\n")
#> Sorted Tuple : (10, 13, 14, 17, 20)
# ── Summary Statistics ────────────────────────────────────────
cat("\nMin     :", min(numbers),  "\n")
#> 
#> Min     : 10
cat("Max     :", max(numbers),  "\n")
#> Max     : 20
cat("Sum     :", sum(numbers),  "\n")
#> Sum     : 74
cat("Average :", mean(numbers), "\n")
#> Average : 14.8

3.3 Visualisation

barplot(
  sort(numbers),
  names.arg = sort(numbers),
  col       = "#2E5FA3",
  border    = "white",
  main      = "Input Numbers (Sorted Ascending)",
  xlab      = "Value",
  ylab      = "Frequency",
  ylim      = c(0, max(numbers) * 1.15)
)
abline(h = mean(numbers), col = "red", lty = 2, lwd = 2)
legend("topleft", legend = paste("Mean =", mean(numbers)),
       col = "red", lty = 2, bty = "n")


4 Question IV – Quadratic Equation Solver

4.1 Problem Statement

Read coefficients a, b, c of \(ax^2 + bx + c = 0\) using a read_coefficients() function, then compute roots via compute_roots().

\[x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}\]

Handle real roots (discriminant ≥ 0) and complex roots (discriminant < 0).

4.2 R Solution

# =============================================================
# Question IV: Quadratic Equation Solver
# =============================================================

# ── Function 1: read_coefficients ────────────────────────────
# Purpose : Prompt the user for coefficients a, b, and c.
# Returns : A named numeric vector c(a=..., b=..., c=...)
read_coefficients <- function() {
  a <- as.numeric(readline("Enter coefficient a: "))
  b <- as.numeric(readline("Enter coefficient b: "))
  c <- as.numeric(readline("Enter coefficient c: "))

  # Validate inputs
  if (any(is.na(c(a, b, c)))) stop("All coefficients must be numeric.")

  return(c(a = a, b = b, c = c))
}

# ── Function 2: compute_roots ────────────────────────────────
# Purpose : Apply the quadratic formula.
#           Returns complex roots when discriminant < 0.
# Params  : a, b, c – numeric coefficients
# Returns : Named list with root1 and root2
compute_roots <- function(a, b, c) {

  if (a == 0) stop("Coefficient 'a' cannot be zero (not a quadratic).")

  discriminant <- b^2 - 4 * a * c   # Value under the square root

  if (discriminant > 0) {
    # Two distinct real roots
    root1 <- (-b + sqrt(discriminant)) / (2 * a)
    root2 <- (-b - sqrt(discriminant)) / (2 * a)
    cat("Discriminant > 0: Two distinct REAL roots.\n")

  } else if (discriminant == 0) {
    # One repeated real root
    root1 <- -b / (2 * a)
    root2 <- root1
    cat("Discriminant = 0: One repeated REAL root.\n")

  } else {
    # as.complex() allows sqrt() to return an imaginary value
    root1 <- (-b + sqrt(as.complex(discriminant))) / (2 * a)
    root2 <- (-b - sqrt(as.complex(discriminant))) / (2 * a)
    cat("Discriminant < 0: Two COMPLEX roots.\n")
  }

  return(list(root1 = root1, root2 = root2))
}

# ── Demo: run two examples without readline() ─────────────────

# Example 1: x^2 - 5x + 6 = 0  →  roots: 3 and 2 (real)
cat("\n--- Example 1: x^2 - 5x + 6 = 0 ---\n")
#> 
#> --- Example 1: x^2 - 5x + 6 = 0 ---
r1 <- compute_roots(a = 1, b = -5, c = 6)
#> Discriminant > 0: Two distinct REAL roots.
cat("Root 1:", r1$root1, "\n")
#> Root 1: 3
cat("Root 2:", r1$root2, "\n")
#> Root 2: 2
# Example 2: x^2 + 2x + 5 = 0  →  complex roots
cat("\n--- Example 2: x^2 + 2x + 5 = 0 ---\n")
#> 
#> --- Example 2: x^2 + 2x + 5 = 0 ---
r2 <- compute_roots(a = 1, b = 2, c = 5)
#> Discriminant < 0: Two COMPLEX roots.
cat("Root 1:", r2$root1, "\n")
#> Root 1: -1+2i
cat("Root 2:", r2$root2, "\n")
#> Root 2: -1-2i
# Example 3: x^2 - 4x + 4 = 0  →  one repeated root
cat("\n--- Example 3: x^2 - 4x + 4 = 0 ---\n")
#> 
#> --- Example 3: x^2 - 4x + 4 = 0 ---
r3 <- compute_roots(a = 1, b = -4, c = 4)
#> Discriminant = 0: One repeated REAL root.
cat("Root 1:", r3$root1, "\n")
#> Root 1: 2
cat("Root 2:", r3$root2, "\n")
#> Root 2: 2

4.3 Interactive Version (run outside of knit)

# eval=FALSE prevents this from blocking the knit process
cat("=============================================\n")
cat("       Quadratic Equation Solver\n")
cat("         ax^2 + bx + c = 0\n")
cat("=============================================\n")

coeffs <- read_coefficients()
roots  <- compute_roots(coeffs["a"], coeffs["b"], coeffs["c"])

cat("\nRoot 1:", roots$root1, "\n")
cat("Root 2:", roots$root2, "\n")

4.4 Visualisation – Parabola Plot (Example 1)

# Plot the parabola for Example 1: x^2 - 5x + 6
a_val <- 1; b_val <- -5; c_val <- 6
x <- seq(-1, 6, length.out = 300)
y <- a_val * x^2 + b_val * x + c_val

plot(x, y, type = "l", col = "#2E5FA3", lwd = 2,
     main = expression(x^2 - 5*x + 6 == 0),
     xlab = "x", ylab = "f(x)")
abline(h = 0, col = "grey50", lty = 2)
abline(v = c(r1$root1, r1$root2), col = "red", lty = 2)
points(c(r1$root1, r1$root2), c(0, 0), pch = 19, col = "red", cex = 1.5)
legend("top",
       legend = c("f(x)", paste("Roots:", r1$root1, "and", r1$root2)),
       col = c("#2E5FA3", "red"), lty = c(1, 2), bty = "n")


5 Question V – Title Case & Descending Sort

5.1 Problem Statement

Accept a sequence of lines, convert each to Title Case, sort them in descending alphabetical order, and print the result.

5.2 R Solution

# =============================================================
# Question V: Title Case Conversion and Descending Sort
# =============================================================

# ── Helper: to_title_case ────────────────────────────────────
# Purpose : Capitalise the first letter of every word and
#           lowercase the remaining letters.
# Param   : line – a single character string
# Returns : The string in Title Case
to_title_case <- function(line) {
  words <- strsplit(line, " ")[[1]]          # Split on spaces

  titled <- sapply(words, function(w) {
    paste0(toupper(substring(w, 1, 1)),       # First character → UPPER
           tolower(substring(w, 2)))          # Rest of word    → lower
  })

  paste(titled, collapse = " ")              # Rejoin into one string
}

# ── Demo input (from the exercise poem) ──────────────────────
lines_in <- c(
  "The scientific method is the way to go",
  "When you absolutely definitely need to know",
  "How things happen in our work everyday",
  "Scientists helps show all of us the way"
)

cat("Original lines:\n")
#> Original lines:
for (l in lines_in) cat(" ", l, "\n")
#>   The scientific method is the way to go 
#>   When you absolutely definitely need to know 
#>   How things happen in our work everyday 
#>   Scientists helps show all of us the way
# ── Convert each line to Title Case ──────────────────────────
titled_lines <- sapply(lines_in, to_title_case, USE.NAMES = FALSE)

# ── Sort descending (reverse alphabetical) ───────────────────
sorted_lines <- sort(titled_lines, decreasing = TRUE)

# ── Print results ─────────────────────────────────────────────
cat("\nSorted output (Title Case, Descending):\n")
#> 
#> Sorted output (Title Case, Descending):
for (l in sorted_lines) cat(" ", l, "\n")
#>   When You Absolutely Definitely Need To Know 
#>   The Scientific Method Is The Way To Go 
#>   Scientists Helps Show All Of Us The Way 
#>   How Things Happen In Our Work Everyday

5.3 Interactive Version (run outside of knit)

# eval=FALSE prevents blocking the knit process
cat("Enter lines (blank line to finish):\n")
lines_in <- character(0)

repeat {
  line <- readline(prompt = "> ")
  if (nchar(trimws(line)) == 0) break
  lines_in <- c(lines_in, line)
}

titled_lines <- sapply(lines_in, to_title_case, USE.NAMES = FALSE)
sorted_lines <- sort(titled_lines, decreasing = TRUE)

cat("\n--- Output ---\n")
for (l in sorted_lines) cat(l, "\n")

End of solutions — Adventist University of Central Africa • May 2026