#include <stdio.h>
#include "../../include/rt_fix.h"

/*
 * reads the time stamp counter of the Pentium CPU.
 * InOut:
 *  long long value     variable to store the time stamp
 *                      counter in.
 * Post:
 *  value contains the value of the time stamp counter.
 */
#define READ_TIME_COUNTER(value)   \
({                                 \
    __asm__ __volatile__ (         \
        ".byte 0x0f; .byte 0x31"   \
        : "=A" (value)             \
        : : "eax", "edx");         \
})


int
main(int argc, char **argv)
{
    int i;
    long long before, after;
    long long cycles_fpu, cycles_nofpu;
    rt_fix fix_1, fix_2, fix_3;
    double x_1, x_2, x_3;

    printf("\n");
    printf("Comparing assignments\n");
    printf("---------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_1 = fix_2;
        } else {
            fix_1 = fix_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_1 = x_2;
        } else {
            x_1 = x_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing comparison\n");
    printf("--------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            rt_fix_eq(fix_1, fix_2);
        } else {
            rt_fix_eq(fix_1, fix_3);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; i = 0; before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_1 == x_2;
        } else {
            x_1 == x_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing modf\n");
    printf("--------------\n");
    rt_fix_init_d(&fix_1, 10. / 3.);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_modf(fix_1, &fix_2);
        } else {
            fix_3 = rt_fix_modf(fix_3, &fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10. / 3.; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = modf(x_1, &x_2);
        } else {
            x_3 = modf(x_3, &x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing additions\n");
    printf("-------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_add(fix_1, fix_2);
        } else {
            fix_3 = rt_fix_add(fix_1, fix_3);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = x_1 + x_2;
        } else {
            x_3 = x_1 + x_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing subtractions\n");
    printf("----------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_sub(fix_1, fix_2);
        } else {
            fix_3 = rt_fix_sub(fix_1, fix_3);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = x_1 - x_2;
        } else {
            x_3 = x_1 - x_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing multiplications\n");
    printf("-------------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_mul(fix_1, fix_2);
        } else {
            fix_3 = rt_fix_mul(fix_1, fix_3);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = x_1 * x_2;
        } else {
            x_3 = x_1 * x_3;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing divisions\n");
    printf("-------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_div(fix_1, fix_2);
        } else {
            fix_3 = rt_fix_div(fix_2, fix_1);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = x_1 / x_2;
        } else {
            x_3 = x_2 / x_1;
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing square root\n");
    printf("---------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_sqrt(fix_1);
        } else {
            fix_3 = rt_fix_sqrt(fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = sqrt(x_1);
        } else {
            x_3 = sqrt(x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing logarithm\n");
    printf("-------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_log(fix_1);
        } else {
            fix_3 = rt_fix_log(fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = log(x_1);
        } else {
            x_3 = log(x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing logarithm to the base of 10\n");
    printf("-------------------------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_log10(fix_1);
        } else {
            fix_3 = rt_fix_log10(fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = log10(x_1);
        } else {
            x_3 = log10(x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing exponential function\n");
    printf("------------------------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_exp(fix_1);
        } else {
            fix_3 = rt_fix_exp(fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = exp(x_1);
        } else {
            x_3 = exp(x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");

    printf("Comparing sine\n");
    printf("--------------\n");
    rt_fix_init_i(&fix_1, 10);
    rt_fix_init_i(&fix_2, 20);
    rt_fix_init_i(&fix_3, 30);
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            fix_3 = rt_fix_sin(fix_1);
        } else {
            fix_3 = rt_fix_sin(fix_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_nofpu = after - before;

    x_1 = 10; x_2 = 20; x_3 = 30;
    before = after = 0;
    READ_TIME_COUNTER(before);
    for(i = 0; i < 10000; i++) {
        if(i & 1) {
            x_3 = sin(x_1);
        } else {
            x_3 = sin(x_2);
        }
    }
    READ_TIME_COUNTER(after);
    cycles_fpu = after - before;
    printf("cycles using no FPU = %Ld\n", cycles_nofpu);
    printf("cycles using FPU    = %Ld\n", cycles_fpu);
    printf("nofpu / fpu         = %Lf\n", (long double)cycles_nofpu / (long double)cycles_fpu);
    printf("\n");
}

