#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>

double f(double x) {
    return pow((x / 100.0 - 5), 5)
         - pow((x / 50.0 + 10), 4)
         - pow((x / 25.0 - 15), 3)
         - pow(x, 2)
         - 10;
}

int ask_iteration_limit(int *max_iter) {
    int choice;
    printf("\n--- Iteration limit reached (%d) ---\n", *max_iter);
    printf("1. Continue with the same number of iterations\n");
    printf("2. Calculate until the end (ignore limit)\n");
    printf("3. Exit and show current result\n");
    printf("Your choice: ");

    if (scanf("%d", &choice) != 1) {
        while(getchar() != '\n');
        return 0;
    }

    if (choice == 1) {
        return 1; // Продовжити, ліміт додасться у циклі
    } else if (choice == 2) {
        *max_iter = 2000000000; // Встановити дуже великий ліміт
        return 1;
    } else {
        return 0; // Вихід
    }
}

void method_half_division(double a, double b, double eps, int max_iter, int debug) {
    double x, fa, fb, fx;
    int iter = 0;
    int limit_step = max_iter;
    clock_t start, end;


    if (f(a) * f(b) > 0) {
        printf("\nError: Function has same signs at a and b. Root might not exist or there are multiple roots.\n");
        return;
    }

    start = clock(); // Початок відліку часу
    printf("\n--- Bisection Method ---\n");

    // Форматування заголовка таблиці
    if (debug) printf("| Iter |       a       |       b       |       x       |      f(x)     |\n");

    do {
        iter++;
        x = (a + b) / 2.0; // Середина відрізка
        fx = f(x);
        fa = f(a);

        // Виведення проміжних результатів у режимі налагодження (широкий формат)
        if (debug) {
            printf("| %4d | %13.6f | %13.6f | %13.6f | %13.6e |\n", iter, a, b, x, fx);
        }

        // Звуження інтервалу
        if (fa * fx < 0) {
            b = x;
        } else {
            a = x;
        }

        // Перевірка ліміту ітерацій
        if (iter >= max_iter) {
            int action = ask_iteration_limit(&limit_step);
            if (action == 0) break; // Вихід з циклу
            max_iter += limit_step; // Збільшення ліміту
        }

    } while (fabs(b - a) > eps && fabs(fx) > eps);

    end = clock(); // Кінець відліку часу
    double time_spent = (double)(end - start) / CLOCKS_PER_SEC;

    printf("\nResults:\n");
    printf("Root x = %.8f\n", x);
    printf("Value f(x) = %.8e\n", f(x));
    printf("Iterations: %d\n", iter);
    printf("Time elapsed: %.6f sec\n", time_spent);
}

// Метод хорд (Chord/Secant Method)
void method_chords(double a, double b, double eps, int max_iter, int debug) {
    double x_curr, x_prev, fa, fb, fx;
    int iter = 0;
    int limit_step = max_iter;
    clock_t start, end;

    // Перевірка наявності кореня
    if (f(a) * f(b) > 0) {
        printf("\nError: Function has same signs at a and b.\n");
        return;
    }

    start = clock();
    printf("\n--- Chord Method ---\n");

    // Форматування заголовка таблиці
    if (debug) printf("| Iter |       a       |       b       |       x       |      f(x)     |\n");

    x_curr = a;
    x_prev = b;

    do {
        iter++;

        fa = f(a);
        fb = f(b);

        // Формула методу хорд
        x_curr = a - (fa * (b - a)) / (fb - fa);
        fx = f(x_curr);

        // Широкий формат виводу
        if (debug) {
            printf("| %4d | %13.6f | %13.6f | %13.6f | %13.6e |\n", iter, a, b, x_curr, fx);
        }

        // Вибір нового інтервалу
        if (f(a) * fx < 0) {
            b = x_curr;
        } else {
            a = x_curr;
        }

        // Перевірка ліміту ітерацій
        if (iter >= max_iter) {
            int action = ask_iteration_limit(&limit_step);
            if (action == 0) break;
            max_iter += limit_step;
        }

        // Умова виходу
    } while (fabs(fx) > eps && fabs(b - a) > eps);

    end = clock();
    double time_spent = (double)(end - start) / CLOCKS_PER_SEC;

    printf("\nResults:\n");
    printf("Root x = %.8f\n", x_curr);
    printf("Value f(x) = %.8e\n", f(x_curr));
    printf("Iterations: %d\n", iter);
    printf("Time elapsed: %.6f sec\n", time_spent);
}

int main() {
    double a, b, eps;
    int max_iter, choice, debug;
    printf("Function: f(x) = (x/100-5)^5 - (x/50+10)^4 - (x/25-15)^3 - x^2 - 10\n\n");

    while (1) {
        printf("\n================ MENU ================\n");
        printf("1. Input data (interval, error, limit)\n");
        printf("2. Bisection Method\n");
        printf("3. Chord Method\n");
        printf("4. Exit\n");
        printf("Select option: ");

        if (scanf("%d", &choice) != 1) {
            while(getchar() != '\n');
            continue;
        }

        if (choice == 1) {
            printf("Enter start of interval (a) [try 4000]: ");
            scanf("%lf", &a);
            printf("Enter end of interval (b) [try 6000]: ");
            scanf("%lf", &b);
            printf("Enter precision (eps, e.g. 0.001): ");
            scanf("%lf", &eps);
            printf("Enter iteration limit (e.g. 100): ");
            scanf("%d", &max_iter);
            printf("Enable debug mode (show table)? (1-Yes, 0-No): ");
            scanf("%d", &debug);
        } else if (choice == 2) {
            method_half_division(a, b, eps, max_iter, debug);
        } else if (choice == 3) {
            method_chords(a, b, eps, max_iter, debug);
        } else if (choice == 4) {
            printf("Exiting program.\n");
            break;
        } else {
            printf("Invalid choice.\n");
        }
    }

    return 0;
}
