#include <stdio.h>

void representationerror(void) {
    // 0.1 = 1/16 + 1/32 + 1/256 + 1/512 + 1/4096 + 1/8192 + ...
    double d1 = 0.1;
    double d2 = 0.3;
    double d  = d1 + d1 + d1;

    printf("\nRepresentation error:\n");
    printf("d1                  = %16g = %23.17g = %25a\n", d1, d1, d1);
    printf("d2                  = %16g = %23.17g = %25a\n", d2, d2, d2);
    printf("d = d1 + d1 + d1    = %16g = %23.17g = %25a\n", d, d, d);
    printf("d - d2              = %16g = %23.17g = %25a\n", (d - d2), (d - d2), (d - d2));
}

void precission(void) {
    double d1 = 12345.0;
    double d2 = 1e-16;

    // we have 53 bits, that is 53 digits in base 2
    // that is aprox 16 digits in base 10
    // 
    // for 1.2345e+4 + 1e-16 we need aprox 20 digits in base 10...
    printf("\nPrecission:\n");
    printf("d1                  = %16g = %23.17g = %25a\n", d1, d1, d1);
    printf("d2                  = %16g = %23.17g = %25a\n", d2, d2, d2);
    printf("d1 + d2             = %16g = %23.17g = %25a\n", (d1 + d2), (d1 + d2), (d1 + d2));
}

void overflow(void) {
    double d1 = 1.6e308;
    double d2 = d1 * 2.0;

    // multiplication and division are separated, because gcc 
    // optimizes (d1 * 2.0) / 2.0 to d1
    d2 /= 2.0;

    // we expect d1 == d2, not so...
    printf("\nOverflow:\n");
    printf("d1                  = %16g = %23.17g = %25a\n", d1, d1, d1);
    printf("d2 = (d1*2.0) / 2.0 = %16g = %23.17g = %25a\n", d2, d2, d2);
}

int main(void) {
    representationerror();
    precission();
    overflow();
    
    return 0;
}

