Last active
January 14, 2018 07:19
-
-
Save itolosa/ddd774bb55b08213d9122d4141336ae8 to your computer and use it in GitHub Desktop.
Clock app in C
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 <limits.h> | |
#include <stdio.h> | |
#include <time.h> | |
#include <unistd.h> | |
#include <sys/time.h> | |
#include <stdint.h> | |
#include <math.h> | |
#include <string.h> | |
#ifdef __MACH__ | |
#include <mach/clock.h> | |
#include <mach/mach.h> | |
#import <mach/mach_time.h> | |
#endif | |
#ifndef EXIT_FAILURE | |
#define EXIT_FAILURE 1 | |
#define EXIT_SUCCESS 0 | |
#endif | |
#define FORMAT_LEN 10 | |
#ifndef NSEC_PER_SEC | |
#define NSEC_PER_SEC UINT64_C(1000000000) | |
#endif | |
#define ARG_INT 0 | |
#define ARG_UINT 1 | |
#define ARG_LINT 2 | |
#define ARG_LUINT 3 | |
#define ARG_REC 'R' | |
#define ARG_SEC 'S' | |
#define ARG_EXIT_AT_OF 'E' | |
typedef enum {false=0, true=1} bool; | |
int int_limit = INT_MAX; | |
long int lint_limit = LONG_MAX; | |
unsigned int uint_limit = UINT_MAX; | |
long unsigned int luint_limit = ULONG_MAX; | |
double int_limit_log; | |
double lint_limit_log; | |
double uint_limit_log; | |
double luint_limit_log; | |
int get_wall_time(struct timespec *ts) | |
{ | |
#ifdef __MACH__ | |
mach_timebase_info_data_t info; | |
if (mach_timebase_info(&info) != KERN_SUCCESS) { | |
printf ("mach_timebase_info failed\n"); | |
return -1; | |
} | |
uint64_t nsec_time = mach_absolute_time() * info.numer / info.denom; | |
ts->tv_sec = nsec_time / NSEC_PER_SEC; | |
ts->tv_nsec = nsec_time - (ts->tv_sec * NSEC_PER_SEC); | |
return 0; | |
#elif defined(CLOCK_MONOTONIC) | |
return clock_gettime(CLOCK_MONOTONIC, ts); | |
#else | |
return clock_gettime(CLOCK_REALTIME, ts); | |
#endif | |
} | |
double wall_time_diff(struct timespec *start, struct timespec *end) | |
{ | |
double delta_s = end->tv_sec - start->tv_sec; | |
double delta_ns = end->tv_nsec - start->tv_nsec; | |
return delta_s + (delta_ns / NSEC_PER_SEC); | |
} | |
double cpu_time_diff(clock_t start, clock_t end) | |
{ | |
return ((double) (end - start)) / CLOCKS_PER_SEC; | |
} | |
bool mult_log_overflow(long unsigned int a, | |
long unsigned int b, double limit_log) { | |
return ((log(a)+log(b)) > limit_log) ? true : false; | |
} | |
int int_rc_factorial(int num) | |
{ | |
if (num < 2) return 1; | |
int result = int_rc_factorial(num-1); | |
if (result == 0) { | |
return 0; | |
} else if (mult_log_overflow(result, num, int_limit_log)) { | |
printf("int_rc_factorial: Overflow at %d * %d\n", result, num); | |
return 0; | |
} | |
return result*num; | |
} | |
int int_r_factorial(int num) | |
{ | |
if (num < 2) return 1; | |
return int_r_factorial(num-1) * num; | |
} | |
unsigned int uint_rc_factorial(unsigned int num) | |
{ | |
if (num < 2) return 1; | |
unsigned int result = uint_rc_factorial(num-1); | |
if (result == 0) { | |
return 0; | |
} else if (mult_log_overflow(result, num, uint_limit_log)) { | |
printf("uint_rc_factorial: Overflow at %u * %u\n", result, num); | |
return 0; | |
} | |
return result*num; | |
} | |
unsigned int uint_r_factorial(unsigned int num) | |
{ | |
if (num < 2) return 1; | |
return uint_r_factorial(num-1)*num; | |
} | |
long int lint_rc_factorial(long int num) | |
{ | |
if (num < 2) return 1; | |
long int result = lint_rc_factorial(num-1); | |
if (result == 0) { | |
return 0; | |
} else if (mult_log_overflow(result, num, lint_limit_log)) { | |
printf("lint_rc_factorial: Overflow at %ld * %ld\n", result, num); | |
return 0; | |
} | |
return result*num; | |
} | |
long int lint_r_factorial(long int num) | |
{ | |
if (num < 2) return 1; | |
return lint_r_factorial(num-1)*num; | |
} | |
long unsigned int luint_rc_factorial(long unsigned int num) { | |
if (num < 2) return 1; | |
long unsigned int result = luint_rc_factorial(num-1); | |
if (result == 0) { | |
return 0; | |
} else if (mult_log_overflow(result, num, luint_limit_log)) { | |
printf("luint_rc_factorial: Overflow at %lu * %lu\n", result, num); | |
return 0; | |
} | |
return result*num; | |
} | |
long unsigned int luint_r_factorial(long unsigned int num) { | |
if (num < 2) return 1; | |
return luint_r_factorial(num-1)*num; | |
} | |
int int_sc_factorial(int num) { | |
int result = 1; | |
while (num > 1) { | |
if (mult_log_overflow(result, num, int_limit_log)) { | |
printf("int_sc_factorial: Overflow at %d * %d\n", result, num); | |
return 0; | |
} | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
int int_s_factorial(int num) { | |
int result = 1; | |
while (num > 1) { | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
unsigned int uint_sc_factorial(unsigned int num) { | |
unsigned int result = 1; | |
while (num > 1) { | |
if (mult_log_overflow(result, num, uint_limit_log)) { | |
printf("uint_sc_factorial: Overflow at %u * %u\n", result, num); | |
return 0; | |
} | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
unsigned int uint_s_factorial(unsigned int num) { | |
unsigned int result = 1; | |
while (num > 1) { | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
long int lint_sc_factorial(long int num) { | |
long int result = 1; | |
while (num > 1) { | |
if (mult_log_overflow(result, num, lint_limit_log)) { | |
printf("lint_sc_factorial: Overflow at %ld * %ld\n", result, num); | |
return 0; | |
} | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
long int lint_s_factorial(long int num) { | |
long int result = 1; | |
while (num > 1) { | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
long unsigned int luint_sc_factorial(long unsigned int num) { | |
long unsigned int result = 1; | |
while (num > 1) { | |
if (mult_log_overflow(result, num, luint_limit_log)) { | |
printf("luint_sc_factorial: Overflow at %lu * %lu\n", result, num); | |
return 0; | |
} | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
long unsigned int luint_s_factorial(long unsigned int num) { | |
long unsigned int result = 1; | |
while (num > 1) { | |
result *= num; | |
num--; | |
} | |
return result; | |
} | |
long unsigned int get_factorial_max_input(long unsigned int limit) { | |
long unsigned int result = 1; | |
long unsigned int count = 1; | |
double limit_log = log(limit); | |
bool overflow_flag = false; | |
while (!overflow_flag) { | |
if (mult_log_overflow(result, count, limit_log)) { | |
printf("Overflow at %lu!\n", count); | |
overflow_flag = true; | |
} else { | |
result *= count; | |
count++; | |
} | |
} | |
return count-1; | |
} | |
void print_help(void) { | |
printf("Use: ./factorial [number] [S | R] [T: 0 int | \n\ | |
1 unsigned int | 2 long int | 3 long unsigned int]\n"); | |
return; | |
} | |
// max input for int: 16 | |
// max input for unsigned int: 33 | |
// max input for long int: 25 | |
// max input for long unsigned int: | |
int main(int argc, char **argv) | |
{ | |
clock_t cpu_start_time_f; | |
clock_t cpu_end_time_f; | |
struct timespec wall_start_time_f; | |
struct timespec wall_end_time_f; | |
double elapsed_wall_time_f; | |
double elapsed_cpu_time_f; | |
clock_t cpu_start_time_cf; | |
clock_t cpu_end_time_cf; | |
struct timespec wall_start_time_cf; | |
struct timespec wall_end_time_cf; | |
double elapsed_wall_time_cf; | |
double elapsed_cpu_time_cf; | |
char arg_mode; | |
int arg_type; | |
char arg_check_input; | |
unsigned long int type_limit; | |
char factorial_format[FORMAT_LEN]; | |
bool overflow_input = false; | |
bool global_overflow = false; | |
int_limit_log = log(int_limit); | |
lint_limit_log = log(lint_limit); | |
uint_limit_log = log(uint_limit); | |
luint_limit_log = log(luint_limit); | |
long unsigned int max_input; | |
if (argc < 4) { | |
printf("Error: Too few arguments.\n"); | |
print_help(); | |
} else if (false) { | |
printf("Error: Too many arguments.\n"); | |
print_help(); | |
} else { | |
sscanf(argv[2], "%c", &arg_mode); | |
sscanf(argv[3], "%d", &arg_type); | |
if (argc > 4) { | |
sscanf(argv[4], "%c", &arg_check_input); | |
} | |
if (arg_type == ARG_INT) { | |
int (*cfactorial)(int); | |
int (*factorial)(int); | |
if (arg_mode == ARG_REC) { | |
cfactorial = int_rc_factorial; | |
factorial = int_r_factorial; | |
} else if (arg_mode == ARG_SEC) { | |
cfactorial = int_sc_factorial; | |
factorial = int_s_factorial; | |
} else { | |
printf("Error: wrong arguments.\n"); | |
print_help(); | |
return EXIT_FAILURE; | |
} | |
int result_cf; | |
int result_f; | |
int input_number; | |
strncpy(factorial_format, "%d", FORMAT_LEN); | |
type_limit = int_limit; | |
sscanf(argv[1], factorial_format, &input_number); | |
max_input = get_factorial_max_input(type_limit); | |
if (input_number > max_input) { | |
printf("Warning: input generates overflow.\n"); | |
overflow_input = true; | |
if (arg_check_input == ARG_EXIT_AT_OF) { | |
printf("Quitting!\n"); | |
return EXIT_FAILURE; | |
} | |
} | |
if (get_wall_time(&wall_start_time_f) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_f = clock(); | |
result_f = factorial(input_number); | |
cpu_end_time_f = clock(); | |
if (get_wall_time(&wall_end_time_f) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
if (get_wall_time(&wall_start_time_cf) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_cf = clock(); | |
result_cf = cfactorial(input_number); | |
cpu_end_time_cf = clock(); | |
if (get_wall_time(&wall_end_time_cf) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
elapsed_wall_time_f = wall_time_diff(&wall_start_time_f, | |
&wall_end_time_f); | |
elapsed_cpu_time_f = cpu_time_diff(cpu_start_time_f, | |
cpu_end_time_f); | |
elapsed_wall_time_cf = wall_time_diff(&wall_start_time_cf, | |
&wall_end_time_cf); | |
elapsed_cpu_time_cf = cpu_time_diff(cpu_start_time_cf, | |
cpu_end_time_cf); | |
printf("--------------------\n"); | |
printf("Factorial without check: "); | |
printf(factorial_format, result_f); | |
if (overflow_input) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_f); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_f); | |
printf("--------------------\n"); | |
printf("Factorial with check: "); | |
printf(factorial_format, result_cf); | |
if (result_cf == 0) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_cf); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_cf); | |
} else if (arg_type == ARG_LINT) { | |
long int (*cfactorial)(long int); | |
long int (*factorial)(long int); | |
long int result_f; | |
long int result_cf; | |
long int input_number; | |
if (arg_mode == ARG_REC) { | |
cfactorial = lint_rc_factorial; | |
factorial = lint_r_factorial; | |
} else if (arg_mode == ARG_SEC) { | |
cfactorial = lint_sc_factorial; | |
factorial = lint_s_factorial; | |
} else { | |
printf("Error: wrong arguments.\n"); | |
print_help(); | |
return EXIT_FAILURE; | |
} | |
type_limit = lint_limit; | |
strncpy(factorial_format, "%ld", FORMAT_LEN); | |
sscanf(argv[1], factorial_format, &input_number); | |
max_input = get_factorial_max_input(type_limit); | |
if (input_number > max_input) { | |
printf("Warning: input generates overflow.\n"); | |
overflow_input = true; | |
if (arg_check_input == ARG_EXIT_AT_OF) { | |
printf("Quitting!\n"); | |
return EXIT_FAILURE; | |
} | |
} | |
if (get_wall_time(&wall_start_time_f) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_f = clock(); | |
result_f = factorial(input_number); | |
cpu_end_time_f = clock(); | |
if (get_wall_time(&wall_end_time_f) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
if (get_wall_time(&wall_start_time_cf) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_cf = clock(); | |
result_cf = cfactorial(input_number); | |
cpu_end_time_cf = clock(); | |
if (get_wall_time(&wall_end_time_cf) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
elapsed_wall_time_f = wall_time_diff(&wall_start_time_f, | |
&wall_end_time_f); | |
elapsed_cpu_time_f = cpu_time_diff(cpu_start_time_f, | |
cpu_end_time_f); | |
elapsed_wall_time_cf = wall_time_diff(&wall_start_time_cf, | |
&wall_end_time_cf); | |
elapsed_cpu_time_cf = cpu_time_diff(cpu_start_time_cf, | |
cpu_end_time_cf); | |
printf("--------------------\n"); | |
printf("Factorial without check: "); | |
printf(factorial_format, result_f); | |
if (overflow_input) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_f); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_f); | |
printf("--------------------\n"); | |
printf("Factorial with check: "); | |
printf(factorial_format, result_cf); | |
if (result_cf == 0) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_cf); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_cf); | |
} else if (arg_type == ARG_UINT) { | |
unsigned int (*cfactorial)(unsigned int); | |
unsigned int (*factorial)(unsigned int); | |
unsigned int result_f; | |
unsigned int result_cf; | |
unsigned int input_number; | |
if (arg_mode == ARG_REC) { | |
cfactorial = uint_rc_factorial; | |
factorial = uint_r_factorial; | |
} else if (arg_mode == ARG_SEC) { | |
cfactorial = uint_sc_factorial; | |
factorial = uint_s_factorial; | |
} else { | |
printf("Error: wrong arguments.\n"); | |
print_help(); | |
return EXIT_FAILURE; | |
} | |
type_limit = uint_limit; | |
strncpy(factorial_format, "%u", FORMAT_LEN); | |
sscanf(argv[1], factorial_format, &input_number); | |
max_input = get_factorial_max_input(type_limit); | |
if (input_number > max_input) { | |
printf("Warning: input generates overflow.\n"); | |
overflow_input = true; | |
if (arg_check_input == ARG_EXIT_AT_OF) { | |
printf("Quitting!\n"); | |
return EXIT_FAILURE; | |
} | |
} | |
if (get_wall_time(&wall_start_time_f) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_f = clock(); | |
result_f = factorial(input_number); | |
cpu_end_time_f = clock(); | |
if (get_wall_time(&wall_end_time_f) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
if (get_wall_time(&wall_start_time_cf) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_cf = clock(); | |
result_cf = cfactorial(input_number); | |
cpu_end_time_cf = clock(); | |
if (get_wall_time(&wall_end_time_cf) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
elapsed_wall_time_f = wall_time_diff(&wall_start_time_f, | |
&wall_end_time_f); | |
elapsed_cpu_time_f = cpu_time_diff(cpu_start_time_f, | |
cpu_end_time_f); | |
elapsed_wall_time_cf = wall_time_diff(&wall_start_time_cf, | |
&wall_end_time_cf); | |
elapsed_cpu_time_cf = cpu_time_diff(cpu_start_time_cf, | |
cpu_end_time_cf); | |
printf("--------------------\n"); | |
printf("Factorial without check: "); | |
printf(factorial_format, result_f); | |
if (overflow_input) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_f); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_f); | |
printf("--------------------\n"); | |
printf("Factorial with check: "); | |
printf(factorial_format, result_cf); | |
if (result_cf == 0) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_cf); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_cf); | |
} else if (arg_type == ARG_LUINT) { | |
long unsigned int (*cfactorial)(long unsigned int); | |
long unsigned int (*factorial)(long unsigned int); | |
if (arg_mode == ARG_REC) { | |
cfactorial = luint_rc_factorial; | |
factorial = luint_r_factorial; | |
} else if (arg_mode == ARG_SEC) { | |
cfactorial = luint_sc_factorial; | |
factorial = luint_s_factorial; | |
} else { | |
printf("Error: wrong arguments.\n"); | |
print_help(); | |
return EXIT_FAILURE; | |
} | |
long unsigned int result_f; | |
long unsigned int result_cf; | |
long unsigned int input_number; | |
strncpy(factorial_format, "%lu", FORMAT_LEN); | |
type_limit = luint_limit; | |
sscanf(argv[1], factorial_format, &input_number); | |
max_input = get_factorial_max_input(type_limit); | |
if (input_number > max_input) { | |
printf("Warning: input generates overflow.\n"); | |
overflow_input = true; | |
if (arg_check_input == ARG_EXIT_AT_OF) { | |
printf("Quitting!\n"); | |
return EXIT_FAILURE; | |
} | |
} | |
if (get_wall_time(&wall_start_time_f) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_f = clock(); | |
result_f = factorial(input_number); | |
cpu_end_time_f = clock(); | |
if (get_wall_time(&wall_end_time_f) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
if (get_wall_time(&wall_start_time_cf) != 0) { | |
printf("Failed to get start wall time\n"); | |
return EXIT_FAILURE; | |
} | |
cpu_start_time_cf = clock(); | |
result_cf = cfactorial(input_number); | |
cpu_end_time_cf = clock(); | |
if (get_wall_time(&wall_end_time_cf) != 0) { | |
printf("Failed to get end wall time\n"); | |
return EXIT_FAILURE; | |
} | |
elapsed_wall_time_f = wall_time_diff(&wall_start_time_f, | |
&wall_end_time_f); | |
elapsed_cpu_time_f = cpu_time_diff(cpu_start_time_f, | |
cpu_end_time_f); | |
elapsed_wall_time_cf = wall_time_diff(&wall_start_time_cf, | |
&wall_end_time_cf); | |
elapsed_cpu_time_cf = cpu_time_diff(cpu_start_time_cf, | |
cpu_end_time_cf); | |
printf("--------------------\n"); | |
printf("Factorial without check: "); | |
printf(factorial_format, result_f); | |
if (overflow_input) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_f); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_f); | |
printf("--------------------\n"); | |
printf("Factorial with check: "); | |
printf(factorial_format, result_cf); | |
if (result_cf == 0) { | |
printf(" (overflow)"); | |
global_overflow = true; | |
} | |
printf("\n"); | |
printf("Elapsed CPU time: %lf seconds\n", elapsed_cpu_time_cf); | |
printf("Elapsed wall time: %lf seconds\n", elapsed_wall_time_cf); | |
} else { | |
printf("Error: wrong arguments.\n"); | |
print_help(); | |
return EXIT_FAILURE; | |
} | |
} | |
if (global_overflow) { | |
return EXIT_FAILURE; | |
} | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment