git.haldean.org floating-bar / f085e73
that should do it for data collection Haldean Brown 2 years ago
2 changed file(s) with 146 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
0 CFLAGS := $(CFLAGS) -std=c11 -O3 -Wall -Wextra -Werror -fno-strict-aliasing
1 LDFLAGS := $(LDFLAGS) -lgmp
2
3 fb: fb.o
4
5 all: fb
6
7 clean:
8 rm fb.o fb
9
10 .PHONY: all clean
+135
-0
fb.c less more
0 #include <gmp.h>
1 #include <math.h>
2 #include <stdbool.h>
3 #include <stdint.h>
4 #include <stdio.h>
5 #include <time.h>
6
7 typedef uint32_t int_equiv_t;
8 typedef int_equiv_t fb_t;
9 typedef float flt_equiv_t;
10
11 /* shift 0b111... right by n, then left by n, so you get 0b1111000...,
12 then invert that. */
13 #define N_BITS(n) ~((~(uint32_t)0 >> (n)) << (n))
14
15 //#define TEST_LIMIT ((uint64_t)1 << (8 * sizeof(fb_t)))
16 #define TEST_LIMIT 1000000L
17
18 #define BAR_BITS 5
19 #define ND_BITS 26
20
21 #define SIGN_MASK (1 << (8 * sizeof(fb_t) - 1))
22 #define BAR_MASK (N_BITS(BAR_BITS) << ND_BITS)
23 #define BAR_SHIFT (ND_BITS)
24 #define ND_MASK (~(SIGN_MASK | BAR_MASK))
25
26 int64_t
27 fb_num(fb_t v)
28 {
29 int32_t s = (v & SIGN_MASK) ? -1 : 1;
30 uint32_t b = (v & BAR_MASK) >> BAR_SHIFT;
31 uint32_t nd = (v & ND_MASK);
32 return s * (int32_t) (nd >> b);
33 }
34
35 uint64_t
36 fb_den(fb_t v)
37 {
38 uint32_t b = (v & BAR_MASK) >> BAR_SHIFT;
39 uint32_t nd = (v & ND_MASK);
40 return (nd & N_BITS(b)) | (1 << b);
41 }
42
43 void
44 fb_print(fb_t v) {
45 printf("%u: %ld/%lu\n", v, fb_num(v), fb_den(v));
46 }
47
48 void
49 fb_to_gmp(mpq_t rop, fb_t fb)
50 {
51 mpq_set_si(rop, fb_num(fb), fb_den(fb));
52 }
53
54 void
55 flt_to_gmp(mpq_t rop, flt_equiv_t flt)
56 {
57 /* this converts floats to doubles, but that conversion is exact
58 since doubles are a superset of floats */
59 mpq_set_d(rop, flt);
60 }
61
62 #define BUCKET_COUNT 100000
63 #define BUCKET_SIZE_NUM 1
64 #define BUCKET_SIZE_DEN 20
65
66 mpq_t limits[BUCKET_COUNT];
67 uint64_t fb_hist[BUCKET_COUNT] = {0};
68 uint64_t flt_hist[BUCKET_COUNT] = {0};
69
70 int
71 main()
72 {
73 mpq_t bsize, qv;
74
75 mpq_inits(bsize, qv, NULL);
76 mpq_set_ui(bsize, BUCKET_SIZE_NUM, BUCKET_SIZE_DEN);
77
78 for (uint64_t i = 0; i < BUCKET_COUNT; i++) {
79 mpq_init(limits[i]);
80 mpq_set_ui(limits[i], i, 1);
81 mpq_mul(limits[i], limits[i], bsize);
82 }
83
84 clock_t start = clock();
85 for (uint64_t lv = 0; lv < TEST_LIMIT; lv++) {
86 int_equiv_t v = (int_equiv_t) lv;
87 if (v % 1000000 == 0) {
88 float complete = v / TEST_LIMIT;
89 double elapsed_sec = (double) (clock() - start) / CLOCKS_PER_SEC;
90 double est_rem = elapsed_sec * TEST_LIMIT / v - elapsed_sec;
91 int s = ceil(est_rem);
92 int m = s / 60;
93 s -= 60 * m;
94 int h = m / 60;
95 m -= 60 * h;
96 fprintf(stderr, "%.1f%% (%d/%ld) %02d:%02d:%02d remaining\n",
97 100. * complete, v, TEST_LIMIT, h, m, s);
98 }
99
100 fb_t fb = (fb_t) v;
101 fb_to_gmp(qv, fb);
102 if (mpq_sgn(qv) >= 0) {
103 mpq_div(qv, qv, bsize);
104 double bf = mpq_get_d(qv);
105 int b = floor(bf);
106 if (b >= BUCKET_COUNT) {
107 b = BUCKET_COUNT - 1;
108 }
109 fb_hist[b]++;
110 }
111
112 flt_equiv_t flt = *((flt_equiv_t*)&v);
113 int class = fpclassify(flt);
114 if (__builtin_expect(class != FP_ZERO && class != FP_NORMAL, 0)) {
115 continue;
116 }
117 flt_to_gmp(qv, flt);
118 if (mpq_sgn(qv) >= 0) {
119 mpq_div(qv, qv, bsize);
120 double bf = mpq_get_d(qv);
121 int b = floor(bf);
122 if (b >= BUCKET_COUNT) {
123 b = BUCKET_COUNT - 1;
124 }
125 flt_hist[b]++;
126 }
127 }
128
129 printf("lim,fb,flt\n");
130 for (int i = 0; i < BUCKET_COUNT; i++) {
131 char *limstr = mpq_get_str(NULL, 10, limits[i]);
132 printf("%s,%ld,%ld\n", limstr, fb_hist[i], flt_hist[i]);
133 }
134 }