support atan and atan2
[fpmath-consensus.git] / impl-libc / impl-libc.c
blob17c6bc5e9b57d78f5a147acf596af0f52a8cc750
1 #include <errno.h>
2 #include <math.h>
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <string.h>
7 #include <unistd.h>
9 /* Whether we're looking at 32-bit or 64-bit floats */
10 typedef enum { P_SINGLE, P_DOUBLE } precision;
12 /* What type of arguments we expect, and what we'll give back. */
13 typedef enum {
14 /* */
15 A_UNKNOWN,
16 A__FLT__FLT,
17 A__FLT_FLT__FLT,
18 A__FLT_FLT_FLT__FLT,
19 } argtype;
21 /* Types of functions we could call */
22 typedef float (*f__f32__f32)(float);
23 typedef float (*f__f32_f32__f32)(float, float);
24 typedef float (*f__f32_f32_f32__f32)(float, float, float);
25 typedef double (*f__f64__f64)(double);
26 typedef double (*f__f64_f64__f64)(double, double);
27 typedef double (*f__f64_f64_f64__f64)(double, double, double);
29 /* Wrapper around a function pointer */
30 typedef struct {
31 /* */
32 precision p;
33 argtype a;
35 union {
36 /* */
37 f__f32__f32 f32__f32;
38 f__f32_f32__f32 f32_f32__f32;
39 f__f32_f32_f32__f32 f32_f32_f32__f32;
40 } f32;
42 union {
43 /* */
44 f__f64__f64 f64__f64;
45 f__f64_f64__f64 f64_f64__f64;
46 f__f64_f64_f64__f64 f64_f64_f64__f64;
47 } f64;
49 } action;
51 void usage(void)
53 fprintf(stderr,
54 "usage: impl-libc [-s|-d] -f <function_name> -n <num_inputs>\n");
55 _exit(1);
58 float idf(float f)
60 return f;
63 double idd(double d)
65 return d;
68 void determine_function(const char *f, action *a)
70 if (!strcmp(f, "zzzzzz")) {
71 a->a = A_UNKNOWN;
72 } else if (!strcmp(f, "id")) {
73 a->a = A__FLT__FLT;
74 a->f32.f32__f32 = idf;
75 a->f64.f64__f64 = idd;
76 } else if (!strcmp(f, "atan")) {
77 a->a = A__FLT__FLT;
78 a->f32.f32__f32 = atanf;
79 a->f64.f64__f64 = atan;
80 } else if (!strcmp(f, "atan2")) {
81 a->a = A__FLT_FLT__FLT;
82 a->f32.f32_f32__f32 = atan2f;
83 a->f64.f64_f64__f64 = atan2;
84 } else if (!strcmp(f, "ceil")) {
85 a->a = A__FLT__FLT;
86 a->f32.f32__f32 = ceilf;
87 a->f64.f64__f64 = ceil;
88 } else if (!strcmp(f, "cos")) {
89 a->a = A__FLT__FLT;
90 a->f32.f32__f32 = cosf;
91 a->f64.f64__f64 = cos;
92 } else if (!strcmp(f, "cot")) {
93 a->a = A_UNKNOWN;
94 } else if (!strcmp(f, "floor")) {
95 a->a = A__FLT__FLT;
96 a->f32.f32__f32 = floorf;
97 a->f64.f64__f64 = floor;
98 } else if (!strcmp(f, "fma")) {
99 a->a = A__FLT_FLT_FLT__FLT;
100 a->f32.f32_f32_f32__f32 = fmaf;
101 a->f64.f64_f64_f64__f64 = fma;
102 } else if (!strcmp(f, "exp")) {
103 a->a = A__FLT__FLT;
104 a->f32.f32__f32 = expf;
105 a->f64.f64__f64 = exp;
106 } else if (!strcmp(f, "expm1")) {
107 a->a = A__FLT__FLT;
108 a->f32.f32__f32 = expm1f;
109 a->f64.f64__f64 = expm1;
110 } else if (!strcmp(f, "log")) {
111 a->a = A__FLT__FLT;
112 a->f32.f32__f32 = logf;
113 a->f64.f64__f64 = log;
114 } else if (!strcmp(f, "log1p")) {
115 a->a = A__FLT__FLT;
116 a->f32.f32__f32 = log1pf;
117 a->f64.f64__f64 = log1p;
118 } else if (!strcmp(f, "powr")) {
119 /* libcs don't seem to have powr (yet?), just pow */
120 a->a = A_UNKNOWN;
121 } else if (!strcmp(f, "sin")) {
122 a->a = A__FLT__FLT;
123 a->f32.f32__f32 = sinf;
124 a->f64.f64__f64 = sin;
125 } else if (!strcmp(f, "sqrt")) {
126 a->a = A__FLT__FLT;
127 a->f32.f32__f32 = sqrtf;
128 a->f64.f64__f64 = sqrt;
129 } else if (!strcmp(f, "tan")) {
130 a->a = A__FLT__FLT;
131 a->f32.f32__f32 = tanf;
132 a->f64.f64__f64 = tan;
133 } else if (!strcmp(f, "trunc")) {
134 a->a = A__FLT__FLT;
135 a->f32.f32__f32 = truncf;
136 a->f64.f64__f64 = trunc;
137 } else {
138 fprintf(stderr, "impl-libc: unknown function \"%s\"\n", f);
139 _exit(1);
143 void read_buf(char *b, ssize_t len)
145 ssize_t r;
146 ssize_t total = 0;
148 while (total < len) {
149 r = read(0, (b + total), (len - total));
151 if (!r) {
152 /* EOF */
153 _exit(0);
154 } else if (r == -1) {
155 perror("impl-libc: read");
156 _exit(1);
157 } else {
158 total += r;
163 void write_buf(const char *b, ssize_t len)
165 ssize_t r;
166 ssize_t total = 0;
168 while (total < len) {
169 r = write(1, (b + total), (len - total));
171 if (r == -1) {
172 perror("impl-libc: write");
173 _exit(1);
174 } else {
175 total += r;
180 size_t input_width(argtype a, precision p)
182 size_t w = (p == P_SINGLE) ? 4 : 8;
184 switch (a) {
185 case A_UNKNOWN:
186 break;
187 case A__FLT__FLT:
189 return 1 * w;
190 case A__FLT_FLT__FLT:
192 return 2 * w;
193 case A__FLT_FLT_FLT__FLT:
195 return 3 * w;
198 return (size_t) -1;
201 size_t output_width(argtype a, precision p)
203 size_t w = (p == P_SINGLE) ? 4 : 8;
205 switch (a) {
206 case A_UNKNOWN:
207 break;
208 case A__FLT__FLT:
210 return 1 * w;
211 case A__FLT_FLT__FLT:
213 return 1 * w;
214 case A__FLT_FLT_FLT__FLT:
216 return 1 * w;
219 return (size_t) -1;
222 void io_loop(action a, size_t n)
224 char *in_buf = 0;
225 char *out_buf = 0;
226 size_t in_sz = input_width(a.a, a.p);
227 size_t out_sz = output_width(a.a, a.p);
229 if ((in_sz * n) / n != in_sz) {
230 fprintf(stderr, "impl-libc: input length overflow\n");
231 _exit(1);
234 if ((out_sz * n) / n != out_sz) {
235 fprintf(stderr, "impl-libc: output length overflow\n");
236 _exit(1);
239 if (!(in_buf = malloc(in_sz * n))) {
240 perror("impl-libc: malloc");
241 _exit(1);
244 if (!(out_buf = malloc(out_sz * n))) {
245 perror("impl-libc: malloc");
246 _exit(1);
249 while (1) {
250 read_buf(in_buf, in_sz * n);
252 switch (a.a) {
253 case A_UNKNOWN:
254 fprintf(stderr, "impl-libc: impossible\n");
255 _exit(1);
256 break;
257 case A__FLT__FLT:
259 switch (a.p) {
260 case P_SINGLE:
262 for (size_t j = 0; j < n; ++j) {
263 float *x = (float *) (in_buf + (in_sz *
264 j));
265 float *y = (float *) (out_buf +
266 (out_sz * j));
268 *y = a.f32.f32__f32(*x);
271 break;
272 case P_DOUBLE:
274 for (size_t j = 0; j < n; ++j) {
275 double *x = (double *) (in_buf +
276 (in_sz * j));
277 double *y = (double *) (out_buf +
278 (out_sz * j));
280 *y = a.f64.f64__f64(*x);
283 break;
286 break;
287 case A__FLT_FLT__FLT:
289 switch (a.p) {
290 case P_SINGLE:
292 for (size_t j = 0; j < n; ++j) {
293 float *x1 = (float *) (in_buf + (in_sz *
294 j));
295 float *x2 = (float *) (in_buf + (in_sz *
297 4));
298 float *y = (float *) (out_buf +
299 (out_sz * j));
301 *y = a.f32.f32_f32__f32(*x1, *x2);
304 break;
305 case P_DOUBLE:
307 for (size_t j = 0; j < n; ++j) {
308 double *x1 = (double *) (in_buf +
309 (in_sz * j));
310 double *x2 = (double *) (in_buf +
311 (in_sz * j) +
313 double *y = (double *) (out_buf +
314 (out_sz * j));
316 *y = a.f64.f64_f64__f64(*x1, *x2);
319 break;
322 break;
323 case A__FLT_FLT_FLT__FLT:
325 switch (a.p) {
326 case P_SINGLE:
328 for (size_t j = 0; j < n; ++j) {
329 float *x1 = (float *) (in_buf + (in_sz *
330 j));
331 float *x2 = (float *) (in_buf + (in_sz *
333 4));
334 float *x3 = (float *) (in_buf + (in_sz *
336 8));
337 float *y = (float *) (out_buf +
338 (out_sz * j));
340 *y = a.f32.f32_f32_f32__f32(*x1, *x2,
341 *x3);
344 break;
345 case P_DOUBLE:
347 for (size_t j = 0; j < n; ++j) {
348 double *x1 = (double *) (in_buf +
349 (in_sz * j));
350 double *x2 = (double *) (in_buf +
351 (in_sz * j) +
353 double *x3 = (double *) (in_buf +
354 (in_sz * j) +
355 16);
356 double *y = (double *) (out_buf +
357 (out_sz * j));
359 *y = a.f64.f64_f64_f64__f64(*x1, *x2,
360 *x3);
363 break;
366 break;
369 write_buf(out_buf, out_sz * n);
373 int main(int argc, char **argv)
375 int c = 0;
376 action a = { .p = P_SINGLE };
377 long long n = 0;
379 while ((c = getopt(argc, argv, "sdf:n:")) != -1) {
380 switch (c) {
381 case 's':
382 a.p = P_SINGLE;
383 break;
384 case 'd':
385 a.p = P_DOUBLE;
386 break;
387 case 'f':
388 determine_function(optarg, &a);
389 break;
390 case 'n':
391 errno = 0;
392 n = strtoll(optarg, 0, 0);
394 if (errno) {
395 perror("impl-libc: unparsable");
397 return 1;
400 break;
401 default:
402 usage();
403 break;
407 if (a.a == A_UNKNOWN) {
408 usage();
411 io_loop(a, n);