ch05/agent_math.c41 lines
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
int stn_sqrt(double x, double *root, int *iters) {
double guess = x / 2.0;
*iters = 0;
while (fabs(guess * guess - x) > 1e-10) {
guess = (guess + x / guess) / 2.0;
(*iters)++;
}
*root = guess;
return 0;
}
int stn_factorial(unsigned n, unsigned long long *result) {
long long f = 1;
for (unsigned i = 2; i <= n; i++) {
f *= i;
if (f < 0) return -2; /* "overflow detected" */
}
*result = (unsigned long long)f;
return 0;
}
int stn_mean_sd(const double *v, size_t n, double *mean, double *sd) {
double s = 0, s2 = 0;
for (size_t i = 0; i < n; i++) { s += v[i]; s2 += v[i] * v[i]; }
*mean = s / n;
*sd = sqrt(s2 / n - *mean * *mean);
return 0;
}
int main(int argc, char **argv) {
const char *t = argc > 1 ? argv[1] : "";
if (t[0] == 's') { double r; int it; int rc = stn_sqrt(atof(argv[2]), &r, &it); printf("stn_sqrt(%g) rc=%d iters=%d %.17g\n", atof(argv[2]), rc, it, r); }
if (t[0] == 'f') { unsigned long long f = 0; int rc = stn_factorial((unsigned)atoi(argv[2]), &f); printf("stn_factorial(%d) rc=%d result=%llu\n", atoi(argv[2]), rc, f); }
if (t[0] == 'd') {
double r[3] = {1013.2, 1013.2, 1013.2}, r2[5] = {21.5, 21.6, 21.8, 22.0, 21.9}, m, sd; int rc;
rc = stn_mean_sd(r, 3, &m, &sd); printf("equal rc=%d sd=%g\n", rc, sd);
rc = stn_mean_sd(r2, 5, &m, &sd); printf("temps rc=%d sd=%g\n", rc, sd);
rc = stn_mean_sd(r, 0, &m, &sd); printf("n=0 rc=%d mean=%g sd=%g\n", rc, m, sd);
}
return 0;
}
ch05/ids.txt9 lines
1001
1004
10o1
-1002
99999999999999999999999
2001x
42
1001111111111111111111111111111111111111
ch05/parse_id.c38 lines
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* Parses a whole line as a sensor ID in [1001, 9999].
Returns 0 and sets *out on success, -1 on any error. */
static int parse_sensor_id(const char *s, long *out) {
char *end;
errno = 0;
long v = strtol(s, &end, 10);
if (end == s) return -1; /* no digits */
if (errno == ERANGE) return -1; /* too big */
while (*end == ' ' || *end == '\t') end++;
if (*end != '\n' && *end != '\0') return -1; /* junk */
if (v < 1001 || v > 9999) return -1; /* out of range */
*out = v;
return 0;
}
int main(void) {
char line[32];
while (fgets(line, sizeof line, stdin) != NULL) {
if (strchr(line, '\n') == NULL && !feof(stdin)) {
int c;
while ((c = getchar()) != '\n' && c != EOF) { }
printf("too long -> rejected\n");
continue;
}
long id;
line[strcspn(line, "\n")] = '\0';
if (parse_sensor_id(line, &id) == 0)
printf("%-10s -> sensor %ld\n", line, id);
else
printf("%-10s -> rejected\n", line);
}
return 0;
}
ch05/stn_copy.c29 lines
#include <stdio.h>
#include <string.h>
/* Copies src into dst (capacity cap bytes, cap >= 1).
Always terminates dst. Returns 0 if all of src fit,
1 if it was truncated, -1 on bad arguments. */
int stn_copy(char *dst, size_t cap, const char *src) {
if (dst == NULL || src == NULL || cap == 0) {
return -1;
}
size_t len = strlen(src);
if (len < cap) {
memcpy(dst, src, len + 1); /* + 1 copies the '\0' */
return 0;
}
memcpy(dst, src, cap - 1);
dst[cap - 1] = '\0';
return 1;
}
int main(void) {
const char *names[] = {"PRESSURE-03", "WIND-04", ""};
char name[8];
for (size_t i = 0; i < 3; i++) {
int rc = stn_copy(name, sizeof name, names[i]);
printf("rc = %d, name = \"%s\"\n", rc, name);
}
return 0;
}
ch05/timing.c86 lines
#define _POSIX_C_SOURCE 199309L
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
double stn_sum(const double *x, size_t n) { /* n */
double s = 0.0;
for (size_t i = 0; i < n; i++) s += x[i];
return s;
}
size_t stn_close_pairs(const double *x, size_t n, double tol) {
size_t count = 0; /* n(n-1)/2 */
for (size_t i = 0; i < n; i++)
for (size_t j = i + 1; j < n; j++)
if (fabs(x[i] - x[j]) < tol) count++;
return count;
}
void stn_matmul(const double *a, const double *b, double *c,
size_t n) { /* n*n*n */
for (size_t i = 0; i < n; i++)
for (size_t j = 0; j < n; j++) {
double s = 0.0;
for (size_t k = 0; k < n; k++)
s += a[i*n + k] * b[k*n + j];
c[i*n + j] = s;
}
}
static double now_s(void) {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return (double)t.tv_sec + (double)t.tv_nsec * 1e-9;
}
/* Fill x with pseudo-random temperatures in [15, 25). */
static void fill(double *x, size_t n) {
for (size_t i = 0; i < n; i++) x[i] = 15.0 + 10.0 * (double)rand() / ((double)RAND_MAX + 1.0);
}
/* Best of 5 runs, in milliseconds. */
#define BEST_OF(expr, out) do { double best_ = 1e30; \
for (int r_ = 0; r_ < 5; r_++) { double t0_ = now_s(); expr; \
double dt_ = now_s() - t0_; if (dt_ < best_) best_ = dt_; } \
(out) = best_ * 1e3; } while (0)
/* Build with -DDIV=16 for a quick sanitizer check at small n. */
#ifndef DIV
#define DIV 1
#endif
static volatile double sink; /* stops the optimizer deleting work */
int main(void) {
srand(42);
printf("%-14s %10s %10s %7s\n", "routine", "n", "ms", "ratio");
double prev = 0.0, ms;
for (size_t n = (1u << 21) / DIV; n <= (1u << 25) / DIV; n <<= 1) {
double *x = malloc(n * sizeof *x);
if (x == NULL) return 1;
fill(x, n);
BEST_OF(sink = stn_sum(x, n), ms);
printf("%-14s %10zu %10.2f %7.2f\n", "sum (n)", n, ms, prev > 0 ? ms / prev : 0.0);
prev = ms; free(x);
}
prev = 0.0;
for (size_t n = 2000 / DIV; n <= 32000 / DIV; n <<= 1) {
double *x = malloc(n * sizeof *x);
if (x == NULL) return 1;
fill(x, n);
BEST_OF(sink = (double)stn_close_pairs(x, n, 0.01), ms);
printf("%-14s %10zu %10.2f %7.2f\n", "pairs (n^2)", n, ms, prev > 0 ? ms / prev : 0.0);
prev = ms; free(x);
}
prev = 0.0;
for (size_t n = 128 / DIV; n <= 1024 / DIV; n <<= 1) {
double *a = malloc(n * n * sizeof *a), *b = malloc(n * n * sizeof *b);
double *c = malloc(n * n * sizeof *c);
if (a == NULL || b == NULL || c == NULL) return 1;
fill(a, n * n); fill(b, n * n);
BEST_OF((stn_matmul(a, b, c, n), sink = c[n + 1]), ms);
printf("%-14s %10zu %10.2f %7.2f\n", "matmul (n^3)", n, ms, prev > 0 ? ms / prev : 0.0);
prev = ms; free(a); free(b); free(c);
}
return 0;
}
ch05/traverse.c33 lines
#define _POSIX_C_SOURCE 199309L
#include <stdio.h>
#include <time.h>
#ifndef N
#define N 4096
#endif
static double a[N * N]; /* 4096 x 4096 doubles = 128 MiB */
static double now_s(void) {
struct timespec t;
clock_gettime(CLOCK_MONOTONIC, &t);
return (double)t.tv_sec + (double)t.tv_nsec * 1e-9;
}
int main(void) {
for (size_t k = 0; k < (size_t)N * N; k++) a[k] = 1.0;
double t0 = now_s(), s_row = 0.0;
for (size_t i = 0; i < N; i++) /* row by row: stride 8 B */
for (size_t j = 0; j < N; j++)
s_row += a[i * N + j];
double t1 = now_s(), s_col = 0.0;
for (size_t j = 0; j < N; j++) /* column by column: */
for (size_t i = 0; i < N; i++) /* stride 4096 * 8 bytes */
s_col += a[i * N + j];
double t2 = now_s();
printf("row-wise sum %.0f in %6.1f ms\n", s_row, (t1 - t0) * 1e3);
printf("column-wise sum %.0f in %6.1f ms\n", s_col, (t2 - t1) * 1e3);
printf("ratio column/row = %.1f\n", (t2 - t1) / (t1 - t0));
return 0;
}