correction-4.c

#include <math.h>
#include <stdio.h>
#include <stdlib.h>

struct int_couple {
    int a;
    int b;
};

struct int_couple minmax(int n, int tab[])
{
    struct int_couple res = { tab[0], tab[0] }; // FIXME ce code est foireux si n == 0,
    // proposez une solution pour le rendre robuste a ce cas precis.

    for (int i = 1; i < n; i++) {
        if (tab[i] > res.b)
            res.b = tab[i];
        if (tab[i] < res.a)
            res.a = tab[i];
    }
    return res;
}

int exo1(int argc, char* argv[])
{
    int tab[argc];
    for (int i = 0; i < argc; i++)
        tab[i] = atoi(argv[i]);

    struct int_couple mm = minmax(argc, tab);
    printf("min %d, max %d\n", mm.a, mm.b);
    return 0;
}

///////////////////////////////////////////

// Ceci est une valeur de epsilon franchement arbitraire
#define EPSILON 0.00001

struct coefs {
    double a;
    double b;
    double c;
};

struct roots {
    double r1;
    double r2;
};

double resolv(double x, struct coefs poly)
{
    return poly.a * x * x + poly.b * x + poly.c;
}

void print_poly(struct coefs poly)
{
    printf("f(x) = %lgx**2 + %lgx + %lg\n", poly.a, poly.b, poly.c);
}

struct coefs scan_poly()
{
    struct coefs p;
    printf("Veuillez saisir les 3 coeficients de f séparés par un espace:\n");
    scanf("%lf %lf %lf", &p.a, &p.b, &p.c);
    return p;
}

struct roots real_roots(struct coefs p, double epsilon)
{
    double delta = p.b * p.b - 4 * p.a * p.c;
    if (delta > epsilon) {
        struct roots r = { ((-p.b - sqrt(delta)) / 2 * p.a), ((-p.b + sqrt(delta)) / 2 * p.a) };
        return r;
    }

    double s;
    if (fabs(delta) <= epsilon) {
        // On est proche de zero, on considere que c'est une racine double
        s = -p.b / 2 * p.a;
    } else {
        // L'equitation n'a pas de solution, je n'ai pas insite en cours
        // mais on peut retourner deux nombres qui ne sont 'pas' des nombres (NaN, Not A Number);
        s = nan(0);
    }
    struct roots r = { s, s };
    return r;
}

struct cplx {
    double r, i;
};

struct roots_cplx {
    struct cplx r1, r2;
};

struct roots_cplx cplx_roots(struct coefs p, double epsilon)
{
    // En pratique on aurait modife la fonction precedente, pour les besoin de la correction
    // je reecris la fonction.
    double delta = p.b * p.b - 4 * p.a * p.c;
    if (delta > epsilon) {
        struct roots_cplx r = {
            { ((-p.b - sqrt(delta)) / (2 * p.a)), 0 },
            { ((-p.b + sqrt(delta)) / (2 * p.a)), 0 }
        };
        return r;
    }

    double s = -p.b / (2 * p.a);
    struct roots_cplx r = { { s, 0 }, { s, 0 } };
    if (delta < epsilon) { // solutions complexes
        r.r1.i = sqrt(-delta) / (2 * p.a);
        r.r2.i = -sqrt(-delta) / (2 * p.a);
    }
    return r;
}

void print_cplx(struct cplx n)
{
    if (n.i == 0)
        printf("%lg", n.r);
    else
        printf("%lg+%lgi", n.r, n.i);
}

void print_roots(struct roots r)
{
    if (r.r1 == r.r2) { // ce sont les exactement les memes nombres par construction,
        // C'est donc un des rares cas ou l'égalite (==) est ok.
        printf("racine double = %lg\n", r.r1);
    } else {
        printf("racines = { %lg, %lg }\n", r.r1, r.r2);
    }
}

void print_roots_cplx(struct roots_cplx r)
{
    if (r.r1.r == r.r2.r && r.r1.i == 0 && r.r1.i == 0) { // ce sont les exactement les memes nombres par construction,
        // C'est donc un des rares cas ou l'égalite (==) est ok.
        printf("racine double = ");
        print_cplx(r.r1);
    } else {
        printf("racines = { ");
        print_cplx(r.r1);
        printf(", ");
        print_cplx(r.r2);
        printf(" }\n");
    }
}

int exo2(int argc, char* argv[])
{
    struct coefs p;
    double x;
    if (argc <= 3) {
        p = scan_poly();
    } else {
        p.a = atof(argv[1]);
        p.b = atof(argv[2]);
        p.c = atof(argv[3]);
    }
    print_poly(p);
    if (argc <= 4) {
        printf("veuillez saisir une valeur de x:\n");
        scanf("%lg", &x);
    } else {
        x = atof(argv[4]);
    }
    printf("f(%lg) = %lg", x, resolv(x, p));

    print_roots(real_roots(p, EPSILON));
    print_roots_cplx(cplx_roots(p, EPSILON));

    return 0;
}

///////////////////////////////////////////////////////////////////////////////

struct point {
    // Remarque, cette structure point ressemble comme deux goutes d'eau
    // a la structure racine. Cependant elle ne servent pas les memes besoin,
    // c'est donc pas plus mal qu'elles soient differentes.
    double x, y;
};

struct point scan_point()
{
    struct point p;
    printf("Veuillez saisir les coordonees d'un point séparés par un espace:\n");
    scanf("%lf %lf", &p.x, &p.y);
    return p;
}

void print_point(struct point p)
{
    printf("(%lf ; %lf)", p.x, p.y);
}

double norm(struct point p1, struct point p2)
{
    double a = p2.x - p1.x;
    double b = p2.y - p1.y;
    return sqrt(a*a + b*b);
}

struct triangle {
    struct point sommets[3]; // Un triangle a 3 cotes, on aurait pu les nommer a, b, c ... mais bon
};

enum ttype {
    SCALENE, ISOCELE, RECTANGLE, EQUILATERAL, ISOCELE_RECTANGLE
        // Attention ici c'est une astuce ! On rappelle qu'une enumeration n'est rien de plus
        // qu'un entier nomme (qui commence a zero). Je me suis arrange pour que le nombre de cote
        // de meme longueur tombe bien avec la position dans l'enumeration. De plus si on ajoute 2
        // a un type de triangle on obtien le meme type en rectangle. Le reste du code devient donc
        // trivial. Ce genre d'astuce n'est pas forcement evident a trouver ... mais c'est la vie.
};

enum ttype type_triangle(struct triangle t)
{
    // Je vous laisse introduire epsilon comme des grands (exemple dans l'exo precedent)
    double a = norm(t.sommets[0], t.sommets[1]);
    double b = norm(t.sommets[1], t.sommets[2]);
    double c = norm(t.sommets[2], t.sommets[0]);

    enum ttype type = (a == b) + (b == c) + (c == a);

    if (a*a + b*b  == c*c
        || b*b + c*c  == a*a
        || c*c + a*a  == b*b)
        type += 2;

    return type;
}

void print_ttype(enum ttype type)
{
    // ceci est aussi une astuce pour eviter de faire un switch. Il me semble l'avoir montre en cours,
    // si ce n'est pas le cas, voila, c'est fait !
    char* names[] = { "INCONNU", "SCALENE", "ISOCELE", "RECTANGLE", "EQUILATERAL", "ISOCELE_RECTANGLE" };
    if (type > ISOCELE_RECTANGLE || type < SCALENE)
        type = -1;
    printf("%s", names[type + 1]); // J'ai decale tout le monde de + 1 pour inserer le texte inconnu,
    // cependant dans ce code, il ne devrait jamais apparaitre
}

int exo3(int argc, char* argv[])
{
    struct point a = scan_point();
    struct point b = scan_point();
    printf("La distance de ");
    print_point(a);
    printf(" a ");
    print_point(b);
    printf(" est %lg\n", norm(a, b));

    struct triangle tri = { { a, b, scan_point() } };
    print_ttype(type_triangle(tri));
    return 0;
}