Skip to content

Instantly share code, notes, and snippets.

@robert-saramet
Last active March 28, 2024 15:36
Show Gist options
  • Select an option

  • Save robert-saramet/107d9258c7db712fbd3e53818e5f31ba to your computer and use it in GitHub Desktop.

Select an option

Save robert-saramet/107d9258c7db712fbd3e53818e5f31ba to your computer and use it in GitHub Desktop.
My solutions to certain exercises inspired by the book 'C Programming: A Modern Approach - Second Edition'
#include <math.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void nth_suffix(unsigned int n, char suffix[]) {
if (n > 10 && n < 20) {
strcpy(suffix, "th");
return;
}
switch (n % 10) {
default:
case 0:
strcpy(suffix, "th");
return;
case 1:
strcpy(suffix, "st");
return;
case 2:
strcpy(suffix, "nd");
return;
case 3:
strcpy(suffix, "rd");
return;
}
}
void checkmark(unsigned int n) {
// Offset by n/2 to allow for (short) principal diagonal
unsigned int m = n + n / 2;
for (int row = 0; row < n; row++) {
for (int col = 0; col < m; col++) {
// On (long) secondary diagonal or on (short) principal diagonal of bottom left square
if (row + col == m - 1 || (row >= n / 2 && col == row + n - m))
printf("*");
else
printf(" ");
}
printf("\n");
}
}
float sphere_volume(float r) { return 4.0f / 3.0f * M_PI * pow(r, 3); }
unsigned int tax_calculator(unsigned int cost, unsigned int tax) { return cost + cost * tax / 100; }
double polynomial(double x) { return 3 * pow(x, 5) + 2 * pow(x, 4) - 5 * pow(x, 3) - x * x + 7 * x - 6; }
int cmpfunc(const void *a, const void *b) { return (*(int *) b - *(int *) a); }
void split_bills(unsigned int bills[], int count, unsigned int amount) {
qsort(bills, count, sizeof(unsigned int), cmpfunc);
printf("%u = ", amount);
for (int i = 0; i < count; i++) {
int n = amount / bills[i];
amount %= bills[i];
printf("%dx %d", n, bills[i]);
if (amount == 0)
return;
// If we used all bills and there is leftover money
if (i == count - 1) {
fprintf(stderr, "\nRemaining %u cannot be obtained from the available bills", amount);
return;
}
printf(" + ");
}
}
void calculate_installments(unsigned int amount, float interest, float installments[], unsigned int months) {
float balance = amount;
float monthly_interest = interest / 100.0f / 12.0f;
for (int i = 0; i < months; i++) {
installments[i] = (float) balance / (months - i);
balance -= installments[i];
balance += balance * monthly_interest;
}
}
typedef struct {
int num, denom;
} Fraction;
int gcd(int a, int b) {
int d = 1;
for (int i = 2; i <= ((a < b) ? a : b); i++)
if (a % i == 0 && b % i == 0)
d = i;
return d;
}
int lcm(int a, int b) { return (a * b) / gcd(a, b); }
Fraction f_add(Fraction a, Fraction b) {
int denom = lcm(a.denom, b.denom);
a.num *= denom / a.denom;
b.num *= denom / b.denom;
return (Fraction){a.num + b.num, denom};
}
Fraction f_sub(Fraction a, Fraction b) {
b.num *= -1;
return f_add(a, b);
}
Fraction f_mul(Fraction a, Fraction b) { return (Fraction){a.num * b.num, a.denom * b.denom}; }
Fraction f_div(Fraction a, Fraction b) { return f_mul(a, (Fraction){b.denom, b.num}); }
Fraction f_simplify(Fraction f) {
int _gcd = gcd(f.num, f.denom);
return (Fraction){f.num / _gcd, f.denom / _gcd};
}
// The algorithm as presented in the book
int compute_upc_check_bad(int code[]) {
int even_sum = 0, odd_sum = 0;
for (int i = 0; i < 11; i++)
// Since we index from 0, the (i + 1)th digit is even when i % 2 == 1
if (i % 2) {
even_sum += code[i];
} else {
odd_sum += code[i];
}
odd_sum *= 3;
odd_sum += even_sum;
odd_sum--;
odd_sum %= 10;
return 9 - odd_sum;
}
int compute_upc_check(int code[]) {
int check = 0;
for (int i = 1; i < 12; i++)
if (i % 2)
check += 3 * code[i - 1];
else
check += code[i - 1];
// Brackets for readability
return 9 - (--check % 10);
}
float _commision_formula(unsigned int value, unsigned int fixed, float percentage) {
return fixed + percentage / 100 * value;
}
float commission(unsigned int value) {
if (value < 2500)
return _commision_formula(value, 30, 1.7);
if (value < 6250)
return _commision_formula(value, 56, 0.66);
if (value < 20000)
return _commision_formula(value, 76, 0.34);
if (value < 50000)
return _commision_formula(value, 100, 0.22);
if (value < 500000)
return _commision_formula(value, 155, 0.11);
return _commision_formula(value, 255, 0.09);
}
int main(void) {
enum Program {
Checkmark = 1,
SphereVolume,
TaxCalculator,
Polynomial,
BillSplitter,
LoanPayment,
Fractions,
FormatDates,
PurchaseInfo,
ISBN,
PhoneNumber,
MagicSquare,
BarcodeCheck,
FlipNumber,
BaseConverter,
Commission,
LegalDate,
};
const char *programs[] = {"Checkmark", "Sphere volume", "Tax calculator", "Polynomial", "Bill splitter",
"Loan payment", "Fractions", "Format dates", "Purchase info", "ISBN",
"Phone number", "Magic square", "Barcode check", "Flip number", "Base converter",
"Commission", "Legal date"};
const unsigned int count = sizeof programs / sizeof programs[0];
printf("Available programs:\n");
for (int i = 1; i <= count; i++) {
printf(" %2d. %-20s", i, programs[i - 1]);
if ((i + 1) % 3 == 0)
printf("\n");
}
enum Program selection;
printf("\nPlease select a program [1-%u]: ", count);
scanf("%u", &selection);
getchar();
switch (selection) {
case Checkmark: {
unsigned int n;
printf("Checkmark size: ");
scanf("%u", &n);
checkmark(n);
break;
}
case SphereVolume: {
float r;
printf("Sphere radius: ");
scanf("%f", &r);
printf("Sphere volume: %.2f", sphere_volume(r));
break;
}
case TaxCalculator: {
unsigned int cost, tax;
printf("Cost before tax: ");
scanf("%u", &cost);
printf("Tax percentage: ");
scanf("%u", &tax);
printf("Cost after tax: %u", tax_calculator(cost, tax));
break;
}
case Polynomial: {
double x;
printf("Enter a real number: ");
scanf("%lf", &x);
printf("3x^5 + 2x^4 - 5x^3 -x^2 + 7x - 6 = %.3lf", polynomial(x));
break;
}
case BillSplitter: {
unsigned int bills[10], amount;
int bill_count = 0;
printf("Please enter your desired bill sizes one by one.\nEnter any character to finish.\n");
printf("Example: `5 10 20 100 q`\n");
while (bill_count < 10 && scanf("%u", bills + bill_count) == 1)
bill_count++;
printf("Enter amount to be split into bills: ");
// Specifier %*c is used to consume and discard the character used to terminate reading of bills
scanf("%*c%u", &amount);
split_bills(bills, bill_count, amount);
break;
}
case LoanPayment: {
unsigned int amount, months;
float interest;
printf("Enter loan amount: ");
scanf("%u", &amount);
printf("Enter interest rate: ");
scanf("%f", &interest);
printf("Enter number of installments [months]: ");
scanf("%u ", &months);
float installments[36];
calculate_installments(amount, interest, installments, months);
for (int i = 0; i < months; i++)
printf("Installment %d: %.2f\n", i + 1, installments[i]);
break;
}
case Fractions: {
printf("Enter a simple expression to calculate. Operation are exected in the order they are written.\n");
printf("Make sure there are spaces between fractions and operators but not inside fractions.\n");
printf("Input formatting example: `2/3 + 1/7 * 5/4 = ?`\n");
int num_a = 0, denom_a = 1, num_b, denom_b;
char curr_op = '+', next_op;
Fraction a = (Fraction){num_a, denom_a};
while (scanf("%d%*c%d %c", &num_b, &denom_b, &next_op) == 3) {
Fraction b = (Fraction){num_b, denom_b};
switch (curr_op) {
case '+':
a = f_add(a, b);
break;
case '-':
a = f_sub(a, b);
break;
case '*':
a = f_mul(a, b);
break;
case '/':
a = f_div(a, b);
break;
default:
break;
}
a = f_simplify(a);
curr_op = next_op;
}
printf("Result = %d/%d", a.num, a.denom);
break;
}
case FormatDates: {
int date[3];
printf("Enter a date [MM/DD/YYYY]\n");
printf("Example: `02/27/1918`\n");
scanf("%d/%d/%d", date, date + 1, date + 2);
const char *items[] = {"MM", "DD", "YYYY"};
for (int i1 = 0; i1 < 3; i1++)
for (int i2 = 0; i2 < 3; i2++)
for (int i3 = 0; i3 < 3; i3++)
if (i1 != i2 && i2 != i3 && i1 != i3) {
printf("Formatted as %s/%s/%s, the date is %.2d/%.2d/%.2d\n", items[i1], items[i2],
items[i3], date[i1], date[i2], date[i3]);
}
break;
}
case PurchaseInfo: {
int item;
float price;
char date[9];
printf("Enter item number: ");
scanf("%d", &item);
printf("Enter unit price: ");
scanf("%f", &price);
printf("Enter purchase date [MM/DD/YYYY]: ");
// The date can be parsed with:
// sscanf(date, "%d/%d/%d", date, date + 1, date + 2)
scanf("%s", date);
printf("Item\t\tUnit\t\tPurchase\n\t\tPrice\t\tDate\n%-7d\t\t$%7.2f\t%s", item, price, date);
break;
}
case ISBN: {
int prefix, group, publisher, item, check;
printf("Enter a 13-digit ISBN number.\nExample: `978-0-393-97950-3`\n");
scanf("%d-%d-%d-%d-%d", &prefix, &group, &publisher, &item, &check);
printf("GS1 prefix: %d\nGroup identifier: %d\nPublisher code: %d\nItem number: %d\nCheck digit: %d\n",
prefix, group, publisher, item, check);
break;
}
case PhoneNumber: {
int number[3];
printf("Enter phone number [(XXX) XXX-XXXX]: ");
scanf("(%d)%d-%d", number, number + 1, number + 2);
printf("Your number is %d.%d.%d", number[0], number[1], number[2]);
break;
}
case MagicSquare: {
int nums[16];
printf("Enter 16 numbers separated by spaces: ");
for (int i = 0; i < 16; i++)
scanf("%d", nums + i);
for (int i = 0; i < 4; i++) {
printf("%2d %2d %2d %2d\n", nums[4 * i], nums[4 * i + 1], nums[4 * i + 2], nums[4 * i + 3]);
}
int row_sums[4] = {0}, col_sums[4] = {0}, diagonal_sums[2] = {0};
for (int i = 0; i < 4; i++) {
for (int j = 0; j < 4; j++) {
row_sums[i] += nums[4 * i + j];
col_sums[i] += nums[4 * j + i];
}
diagonal_sums[0] += nums[5 * i];
diagonal_sums[1] += nums[3 * i + 3];
}
printf("Row sums: %d %d %d %d\n", row_sums[0], row_sums[1], row_sums[2], row_sums[3]);
printf("Column sums: %d %d %d %d\n", col_sums[0], col_sums[1], col_sums[2], col_sums[3]);
printf("Principal diagonal sum: %d\nSecondary diagonal sum: %d", diagonal_sums[0], diagonal_sums[1]);
break;
}
case BarcodeCheck: {
int code[12];
printf("Enter a 12-digit UPC barcode: ");
for (int i = 0; i < 12; i++)
// %1d reads a single digit
scanf("%1d", code + i);
int check = compute_upc_check(code);
printf("Computed check is %d\n", check);
bool valid = code[11] == check;
printf("This barcode is %svalid\n", valid ? "" : "not ");
break;
}
case FlipNumber: {
unsigned long long n, m = 0;
printf("Enter a number: ");
scanf("%llu", &n);
while (n) {
m *= 10;
m += n % 10;
n /= 10;
}
printf("The flipped number is %llu", m);
break;
}
case BaseConverter: {
int n;
printf("Enter a number in the base of your choosing.\n");
printf("Base 8 %-14s [123]\n", "(octal):");
printf("Base 10 %-14s [0123]\n", "(decimal):");
printf("Base 16 %-14s [0x123]\n", "(hexadecimal):");
printf("Enter the number: ");
scanf("%i", &n);
printf("%-15s\t%-15s\t%-15s\n%-15d\t0%-14o\t0x%-13x", "Decimal", "Octal", "Hexadecimal", n, n, n);
break;
}
case Commission: {
unsigned int value;
printf("Enter value of trade: ");
scanf("%u", &value);
printf("The broker commission for this trade is %.2f\n", commission(value));
break;
}
case LegalDate: {
typedef enum {
January = 1,
February,
March,
April,
May,
June,
July,
August,
September,
October,
November,
December,
} Month;
Month month;
unsigned int day, year;
char month_str[10], suffix[4];
printf("Enter date [DD/MM/YYYY]: ");
scanf("%d/%d/%d", &day, &month, &year);
nth_suffix(day, suffix);
switch (month) {
case January:
strcpy(month_str, "January");
break;
case February:
strcpy(month_str, "February");
break;
case March:
strcpy(month_str, "March");
break;
case April:
strcpy(month_str, "April");
break;
case May:
strcpy(month_str, "May");
break;
case June:
strcpy(month_str, "June");
break;
case July:
strcpy(month_str, "July");
break;
case August:
strcpy(month_str, "August");
break;
case September:
strcpy(month_str, "September");
break;
case October:
strcpy(month_str, "October");
break;
case November:
strcpy(month_str, "November");
break;
case December:
strcpy(month_str, "December");
break;
}
printf("Dated this %u%s day of %s, %u\n", day, suffix, month_str, year);
break;
}
default: {
fprintf(stderr, "\nError: program not found");
break;
}
}
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment