Last active
March 28, 2024 15:36
-
-
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'
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #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