Skip to content

Instantly share code, notes, and snippets.

@itolosa
Last active January 14, 2018 07:19
Show Gist options
  • Save itolosa/ddd774bb55b08213d9122d4141336ae8 to your computer and use it in GitHub Desktop.
Save itolosa/ddd774bb55b08213d9122d4141336ae8 to your computer and use it in GitHub Desktop.
Clock app in C
#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