From ebd28ec51ddc7621ccbedd18570f3df5bc55b68a Mon Sep 17 00:00:00 2001 From: Mika Date: Sat, 6 Dec 2025 13:41:16 +0000 Subject: [PATCH] Add bootstrap_resampling/main.c --- bootstrap_resampling/main.c | 286 ++++++++++++++++++++++++++++++++++++ 1 file changed, 286 insertions(+) create mode 100644 bootstrap_resampling/main.c diff --git a/bootstrap_resampling/main.c b/bootstrap_resampling/main.c new file mode 100644 index 0000000..e9a1c21 --- /dev/null +++ b/bootstrap_resampling/main.c @@ -0,0 +1,286 @@ +#include +#include +#include +#include + +/* + * bootstrap_resampling CLI + * + * Zweck: + * Einfaches Linux-Kommandozeilenprogramm, das Bootstrap-Resampling + * auf eindimensionalen Leistungsdaten durchführt. + * + * - Liest Werte (double) aus einer Textdatei, ein Wert pro Zeile. + * - Fuehrt Bootstrap-Resampling mit einer konfigurierbaren Anzahl + * an Iterationen durch (Standard: 10000). + * - Berechnet den Bootstrap-Mittelwert, 95-%-Konfidenzintervall + * sowie Outlier anhand einer einfachen z-Score-Heuristik. + * - Ausgabe erfolgt als JSON im Format "bootstrap_results". + * + * Nutzung: + * ./bootstrap_resampling [iterations] + * + * Beispiel: + * ./bootstrap_resampling data.txt 10000 + * + * Einschränkungen / Annahmen: + * - Maximal 1e6 Datenpunkte (anpassbar über MAX_POINTS). + * - Es wird ein sehr einfacher Bootstrap-Ansatz mit fester + * Konfidenz von 95 % (2.5- und 97.5-Perzentil) verwendet. + * - Outlier-Erkennung: |z| > 3 relativ zu Stichprobenmittelwert + * und -standardabweichung der Originaldaten. + */ + +#define MAX_POINTS 1000000 + +/* Struktur für Ergebnisse, passend zur geforderten bootstrap_results-Form: + * { + * "mean": , + * "ci_lower": , + * "ci_upper": , + * "outliers": [, ...] + * } + */ + +typedef struct { + double mean; + double ci_lower; + double ci_upper; + double *outliers; + size_t outlier_count; +} bootstrap_results; + +/* Einfache Funktion zum Einlesen von double-Werten aus einer Datei. */ +static size_t read_data(const char *path, double *buffer, size_t max_points) { + FILE *f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "Error: cannot open input file '%s'\n", path); + return 0; + } + + size_t n = 0; + while (n < max_points && fscanf(f, "%lf", &buffer[n]) == 1) { + n++; + } + + fclose(f); + return n; +} + +/* Berechnung von Mittelwert und Standardabweichung einer Stichprobe. */ +static void mean_std(const double *data, size_t n, double *mean, double *stddev) { + if (n == 0) { + *mean = 0.0; + *stddev = 0.0; + return; + } + + double sum = 0.0; + for (size_t i = 0; i < n; ++i) { + sum += data[i]; + } + double m = sum / (double)n; + + double var = 0.0; + for (size_t i = 0; i < n; ++i) { + double d = data[i] - m; + var += d * d; + } + if (n > 1) { + var /= (double)(n - 1); + } else { + var = 0.0; + } + + *mean = m; + *stddev = var > 0.0 ? sqrt(var) : 0.0; +} + +/* Vergleichsfunktion für qsort von double-Werten. */ +static int cmp_double(const void *a, const void *b) { + double da = *(const double *)a; + double db = *(const double *)b; + if (da < db) return -1; + if (da > db) return 1; + return 0; +} + +/* Erzeugt eine gleichverteilte Zufallszahl im Bereich [0,1). */ +static double urand(void) { + return (double)rand() / ((double)RAND_MAX + 1.0); +} + +/* Führt das eigentliche Bootstrap-Resampling aus. */ +static int run_bootstrap(const double *data, size_t n, long iterations, bootstrap_results *res) { + if (n == 0 || iterations <= 0) { + return -1; + } + + double *boot_means = (double *)malloc((size_t)iterations * sizeof(double)); + if (!boot_means) { + fprintf(stderr, "Error: memory allocation failed for bootstrap means.\n"); + return -1; + } + + /* Bootstrap: mit Zurücklegen aus Originaldaten ziehen und Mittelwert berechnen. */ + for (long it = 0; it < iterations; ++it) { + double sum = 0.0; + for (size_t i = 0; i < n; ++i) { + size_t idx = (size_t)(urand() * (double)n); + if (idx >= n) { + idx = n - 1; /* Sicherheitskappe bei Randfällen */ + } + sum += data[idx]; + } + boot_means[it] = sum / (double)n; + } + + /* Sortieren für Perzentile. */ + qsort(boot_means, (size_t)iterations, sizeof(double), cmp_double); + + /* Perzentil-Indices für 95-%-CI. */ + double lower_p = 0.025; + double upper_p = 0.975; + + long lower_idx = (long)(lower_p * (double)iterations); + long upper_idx = (long)(upper_p * (double)iterations); + + if (lower_idx < 0) lower_idx = 0; + if (upper_idx >= iterations) upper_idx = iterations - 1; + + /* Schätzer für den Bootstrap-Mittelwert: Mittel über alle Bootstrap-Mittelwerte. */ + double mean_boot = 0.0; + for (long it = 0; it < iterations; ++it) { + mean_boot += boot_means[it]; + } + mean_boot /= (double)iterations; + + res->mean = mean_boot; + res->ci_lower = boot_means[lower_idx]; + res->ci_upper = boot_means[upper_idx]; + + free(boot_means); + return 0; +} + +/* Einfache Outlier-Erkennung via z-Score (|z| > 3). */ +static int detect_outliers(const double *data, size_t n, bootstrap_results *res) { + double mean, stddev; + mean_std(data, n, &mean, &stddev); + + if (stddev == 0.0 || n == 0) { + /* Keine Ausreißer, wenn alle Werte identisch sind oder keine Daten vorliegen. */ + res->outliers = NULL; + res->outlier_count = 0; + return 0; + } + + /* Zuerst Anzahl bestimmen. */ + size_t count = 0; + for (size_t i = 0; i < n; ++i) { + double z = (data[i] - mean) / stddev; + if (z > 3.0 || z < -3.0) { + count++; + } + } + + if (count == 0) { + res->outliers = NULL; + res->outlier_count = 0; + return 0; + } + + double *outs = (double *)malloc(count * sizeof(double)); + if (!outs) { + fprintf(stderr, "Error: memory allocation failed for outliers.\n"); + return -1; + } + + size_t idx = 0; + for (size_t i = 0; i < n; ++i) { + double z = (data[i] - mean) / stddev; + if (z > 3.0 || z < -3.0) { + outs[idx++] = data[i]; + } + } + + res->outliers = outs; + res->outlier_count = count; + return 0; +} + +/* Gibt die Ergebnisse als JSON-Objekt auf stdout aus. */ +static void print_results_json(const bootstrap_results *res) { + printf("{\n"); + printf(" \"mean\": %.17g,\n", res->mean); + printf(" \"ci_lower\": %.17g,\n", res->ci_lower); + printf(" \"ci_upper\": %.17g,\n", res->ci_upper); + printf(" \"outliers\": ["); + for (size_t i = 0; i < res->outlier_count; ++i) { + printf("%.17g", res->outliers[i]); + if (i + 1 < res->outlier_count) { + printf(", "); + } + } + printf("]\n"); + printf("}\n"); +} + +int main(int argc, char **argv) { + if (argc < 2) { + fprintf(stderr, "Usage: %s [iterations]\n", argv[0]); + return 1; + } + + const char *input_path = argv[1]; + long iterations = 10000; /* Standardwert analog zur Beschreibung. */ + + if (argc >= 3) { + iterations = strtol(argv[2], NULL, 10); + if (iterations <= 0) { + fprintf(stderr, "Error: iterations must be positive.\n"); + return 1; + } + } + + double *data = (double *)malloc(MAX_POINTS * sizeof(double)); + if (!data) { + fprintf(stderr, "Error: memory allocation failed for input data.\n"); + return 1; + } + + size_t n = read_data(input_path, data, MAX_POINTS); + if (n == 0) { + fprintf(stderr, "Error: no data read from '%s'.\n", input_path); + free(data); + return 1; + } + + /* RNG initialisieren: einfache, reproduzierbare Basis mit Zeitstempel. */ + srand((unsigned int)time(NULL)); + + bootstrap_results res; + res.mean = 0.0; + res.ci_lower = 0.0; + res.ci_upper = 0.0; + res.outliers = NULL; + res.outlier_count = 0; + + if (run_bootstrap(data, n, iterations, &res) != 0) { + free(data); + return 1; + } + + if (detect_outliers(data, n, &res) != 0) { + free(data); + if (res.outliers) free(res.outliers); + return 1; + } + + /* Ausgabe strikt als JSON im Format bootstrap_results. */ + print_results_json(&res); + + free(data); + if (res.outliers) free(res.outliers); + return 0; +}