├── .gitignore ├── Makefile ├── README ├── between.c ├── cf-evaluate ├── cf.c ├── cf.h ├── cf_append.c ├── cf_append.h ├── cf_arith.c ├── cf_arith.h ├── cf_between.c ├── cf_between.h ├── cf_float.c ├── cf_float.h ├── cf_holo.c ├── cf_holo.h ├── cf_it.c ├── cf_it.h ├── cf_per.c ├── cf_per.h ├── cf_rat.c ├── cf_rat.h ├── main.c ├── man ├── demo.1 └── libcf.3 ├── surd.c ├── surd2.c └── t ├── appendtest.c └── arraytest.c /.gitignore: -------------------------------------------------------------------------------- 1 | *.o 2 | *.a 3 | /between 4 | /cf-demo 5 | /man/demo.pdf 6 | /man/demo.ps 7 | /surd 8 | /surd2 9 | /t/appendtest 10 | /t/arraytest 11 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | 2 | # CFLAGS=-DDEBUG_COEFFS -DDEBUG_VARARGS 3 | # CFLAGS=-g 4 | # LDFLAGS=-g 5 | LIBS=-lm 6 | 7 | default: cf-demo between surd surd2 t/appendtest t/arraytest doc 8 | 9 | HDRS= cf.h cf_append.h cf_arith.h cf_between.h cf_float.h cf_holo.h cf_it.h cf_rat.h cf_per.h 10 | SRCS= cf.c cf_append.c cf_arith.c cf_between.c cf_float.c cf_holo.c cf_it.c cf_rat.c cf_per.c main.c 11 | MANS= man/demo.1 man/libcf.3 12 | 13 | doc: man/demo.ps man/demo.pdf 14 | 15 | cf.o: cf.c cf.h 16 | cf_append.o: cf_append.c cf_append.h cf.h 17 | cf_arith.o: cf_arith.c cf_arith.h cf.h 18 | cf_between.o: cf_between.c cf_between.h cf.h 19 | cf_float.o: cf_float.c cf_float.h cf.h 20 | cf_holo.o: cf_holo.c cf_holo.h cf.h 21 | cf_it.o: cf_it.c cf_it.h cf.h 22 | cf_per.o: cf_per.c cf_per.h cf.h 23 | cf_rat.o: cf_rat.c cf_rat.h cf.h 24 | 25 | cf-demo: main.o libcf.a 26 | $(CC) $(LDFLAGS) -o cf-demo $^ $(LIBS) 27 | 28 | between: between.o libcf.a 29 | $(CC) $(LDFLAGS) -o between $^ $(LIBS) 30 | 31 | t/arraytest: t/arraytest.o libcf.a 32 | $(CC) $(LDFLAGS) -o t/arraytest $^ $(LIBS) 33 | 34 | surd: surd.o libcf.a 35 | $(CC) $(LDFLAGS) -o surd $^ $(LIBS) 36 | 37 | surd2: surd2.o libcf.a 38 | $(CC) $(LDFLAGS) -o surd2 $^ $(LIBS) 39 | 40 | t/appendtest: t/appendtest.o libcf.a 41 | $(CC) $(LDFLAGS) -o t/appendtest $^ $(LIBS) 42 | 43 | libcf.a: cf.o cf_append.o cf_arith.o cf_between.o cf_rat.o cf_float.o cf_holo.o cf_arith.o cf_it.o cf_per.o 44 | ar cr libcf.a $? 45 | ranlib libcf.a 46 | 47 | main.o: main.c cf.h cf_rat.h cf_float.h cf_holo.h cf_arith.h cf_it.h cf_per.h 48 | between.o: between.c cf_between.h cf_rat.h cf.h 49 | arraytest.o: arraytest.c cf_per.h 50 | 51 | clean: 52 | rm -f *.o 53 | 54 | veryclean: clean 55 | rm -f *.a demo cf.tgz 56 | 57 | 58 | dist: cf.tgz 59 | 60 | cf.tgz: $(SRCS) $(HDRS) $(MANS) Makefile 61 | tar czf cf.tgz *.[ch1-9] Makefile 62 | 63 | man/demo.ps: man/demo.1 64 | groff -man man/demo.1 > man/demo.ps 65 | 66 | man/demo.pdf: man/demo.ps 67 | ps2pdf man/demo.ps && mv demo.pdf man 68 | 69 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This is a small library for continued fraction calculations, written 2 | in C. For more details about continued fractions and the algorithms 3 | herein, see 4 | 5 | http://perl.plover.com/yak/cftalk/ 6 | 7 | The library is documented in "libcf.3". 8 | 9 | The Makefile builds a program called "cf-demo" that demonstrates the 10 | library. This is fully documented in "demo.1". A brief usage summary 11 | follows. 12 | 13 | cf-demo num den 14 | 15 | Print the continued fraction expansion of rational number num/den. 16 | For example, "cf-demo 29 8" prints "3 1 1 1 2". 17 | 18 | cf-demo x 19 | 20 | Print the continued fraction expansion of floating point number x. 21 | For example, "cf-demo 1.4142" prints "1 2 2 2 2 2 1 1 29 86 312". 22 | 23 | cf-demo a b c d x 24 | 25 | Print the continued fraction expansion of (ax+b)/(cx+d) where 26 | a,b,c,d are integers and x is real. 27 | 28 | cf-demo a b c d e f g h x y 29 | 30 | 31 | Print the continued fraction expansion of (axy+bx+cy+d)/(exy+fx+gy+h) 32 | where a..h are integers and x and y are real. 33 | 34 | cf-demo x + y 35 | cf-demo x - y 36 | cf-demo x * y 37 | cf-demo x / y 38 | 39 | x and y are first converted to continued fractions, and then the 40 | indicated calculation is performed; for example 'x + y' adds x and y. 41 | Then the resulting continued fraction is printed. For convenience, 42 | 'x' is accepted as a synonym for '*'. 43 | 44 | 45 | -------------------------------------------------------------------------------- /between.c: -------------------------------------------------------------------------------- 1 | 2 | #include "cf.h" 3 | #include "cf_between.h" 4 | #include "cf_rat.h" 5 | #include 6 | #include 7 | #include 8 | 9 | void usage(char *argv0) { 10 | fprintf(stderr, "Usage: %s a/b c/d\n\tFind simplest fraction between a/b and c/d\n", argv0); 11 | fprintf(stderr, "(unimplemented)\n"); 12 | exit(0); 13 | } 14 | 15 | unsigned parserat(char *s, int *n, int *d) { 16 | *n = atoi(s); 17 | 18 | while (*s != '\0' && *s != '/') s++; 19 | 20 | if (*s == '\0') { 21 | *d = 1; 22 | return 1; 23 | } 24 | 25 | s++; 26 | *d = atoi(s); 27 | 28 | return 1; 29 | } 30 | 31 | int main(int argc, char **argv) { 32 | char *prog = argv[0]; 33 | char **arg = argv+1; 34 | int n, d; 35 | CF a[2], r; 36 | 37 | if (argc < 2) usage(prog); 38 | 39 | { 40 | unsigned i; 41 | for (i=0; i<2; i++) 42 | if (parserat(arg[i], &n, &d)) 43 | a[i] = new_rat(n, d); 44 | else 45 | usage(prog); 46 | } 47 | fprintf(stderr, "unimplemented\n"); 48 | return 19; 49 | 50 | r = between(a[0], a[1]); 51 | print_cf(r); 52 | 53 | return 0; 54 | } 55 | 56 | -------------------------------------------------------------------------------- /cf-evaluate: -------------------------------------------------------------------------------- 1 | #!/usr/bin/perl 2 | # 3 | 4 | @ARGV or usage(); 5 | 6 | my $x = [0, 1, 1, 0]; 7 | 8 | sub input { 9 | my ($x, $p) = @_; 10 | my ($a, $b, $c, $d) = @$x; 11 | [ $b, $a + $b*$p, $d, $c + $d*$p ]; 12 | } 13 | 14 | sub val { 15 | my $x = shift; 16 | my ($a, $b, $c, $d) = @$x; 17 | return [$b, $d]; 18 | } 19 | 20 | for (@ARGV) { 21 | $x = input($x, $_); 22 | my $f = val($x); 23 | printf "%8d / %8d %20.20f\n", @$f, $f->[1] && $f->[0] / $f->[1]; 24 | } 25 | 26 | sub usage { 27 | print qq{Usage: $0 a1 a2 a3 ... 28 | The a_i are the partial quotients of a simple continued fraction. 29 | The program will print out the convergents. 30 | }; 31 | exit 1; 32 | } 33 | -------------------------------------------------------------------------------- /cf.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "cf.h" 5 | 6 | static int stub(CF); 7 | 8 | CF 9 | new_cf(size_t s) 10 | { 11 | CF cf = malloc(s); 12 | if (cf == 0) return 0; 13 | cf->DONE = 0; 14 | cf->next = stub; 15 | return cf; 16 | } 17 | 18 | static int 19 | stub(CF cf) 20 | { 21 | fprintf(stderr, "cf: no behavior defined\n"); 22 | exit(1); 23 | } 24 | 25 | int 26 | next(CF cf) { 27 | int t; 28 | 29 | if (cf->DONE) return C_INF; 30 | 31 | t = (cf->next)(cf); 32 | 33 | if (t > TOOBIG) { 34 | cf->DONE = 1; 35 | t = C_INF; 36 | } 37 | 38 | return t; 39 | } 40 | 41 | void 42 | print_cf(CF cf) 43 | { 44 | fprint_cf(stdout, cf); 45 | } 46 | 47 | #define STOP 30 48 | 49 | void 50 | fprint_cf(FILE *f, CF cf) 51 | { 52 | int t; 53 | unsigned stop = STOP; 54 | while ((t = next(cf)) != C_INF) { 55 | fprintf(f, "%d ", t); 56 | if (--stop == 0) break; 57 | } 58 | fputs("\n", f); 59 | } 60 | -------------------------------------------------------------------------------- /cf.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H 3 | #define CF_H 4 | 5 | #define BASE_CF int (*next)(struct st_cf *); char DONE 6 | 7 | typedef struct st_cf { 8 | BASE_CF; 9 | } *CF; 10 | 11 | #include 12 | #define C_INF INT_MAX 13 | #define TOOBIG 65535 14 | 15 | #ifdef DEBUG 16 | #define DEBUG_BOUNDS 17 | #define DEBUG_COEFFS 18 | #define DEBUG_IO 19 | #endif 20 | 21 | #include 22 | int next(CF); 23 | void print_cf(CF); 24 | void fprint_cf(FILE *, CF); 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /cf_append.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "cf.h" 4 | #include "cf_append.h" 5 | #include "cf_per.h" 6 | 7 | static int next_append(CF); 8 | 9 | typedef struct st_cf_append { 10 | BASE_CF; 11 | unsigned pos; 12 | unsigned n_cfs; 13 | CF cf[1]; /* one or more */ 14 | } *CFP; 15 | #define cfp ((CFP)cf) 16 | 17 | static CFP new_cf_append(unsigned n_cfs) 18 | { 19 | CFP result = (CFP) new_cf(sizeof(struct st_cf_append) 20 | + (n_cfs-1) * sizeof(CF)); 21 | if (result) { 22 | result->pos = 0; 23 | result->n_cfs = n_cfs; 24 | } 25 | return result; 26 | } 27 | 28 | CF append1(CF a, int t) 29 | { 30 | CFP result = new_cf_append(2); 31 | if (result == 0) return 0; 32 | 33 | result->cf[0] = a; 34 | result->cf[1] = new_array(t); 35 | result->next = next_append; 36 | return (CF) result; 37 | } 38 | 39 | CF_appendcf(CF a0, ...) 40 | { 41 | unsigned count_items(va_list *); 42 | unsigned n; 43 | va_list va; 44 | 45 | va_start(va, a0); 46 | n = 1 + count_items(&va); 47 | va_end(va); 48 | } 49 | 50 | unsigned 51 | count_items(va_list *ap) 52 | { 53 | unsigned count = 0; 54 | va_list ap_save; 55 | 56 | va_copy(ap_save, *ap); 57 | 58 | while (va_arg(ap_save, int) != 0) count++; 59 | return count; 60 | } 61 | 62 | static int next_append(CF cf) 63 | { 64 | int i = C_INF; 65 | 66 | while (cfp->pos < cfp->n_cfs) { 67 | i = next(cfp->cf[cfp->pos]); 68 | if (i == C_INF) cfp->pos++; 69 | else break; 70 | } 71 | 72 | return i; 73 | } 74 | -------------------------------------------------------------------------------- /cf_append.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_APPEND 3 | #define CF_H_APPEND 4 | 5 | #include "cf.h" 6 | 7 | CF append1(CF, int); 8 | 9 | #endif 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /cf_arith.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include 5 | 6 | #include "cf_arith.h" 7 | 8 | typedef struct st_cf_arith { 9 | BASE_CF; 10 | int a, b, c, d; 11 | int e, f, g, h; 12 | CF x, y; 13 | char x_done, y_done; 14 | } *CFA; 15 | #define cfa ((CFA)cf) 16 | 17 | static int next_arith(CF); 18 | static float bound(int, int); 19 | static void egest(CFA, int); 20 | static void ingest_x(CFA); 21 | static void ingest_y(CFA); 22 | 23 | #define MAX(i, j) ((i) > (j) ? (i) : (j)) 24 | #define IDIFF(p, q) ((p) == C_INF ? C_INF : \ 25 | (q) == C_INF ? C_INF : \ 26 | fabs((p)-(q))) 27 | 28 | CF 29 | new_arith(int a, int b, int c, int d, 30 | int e, int f, int g, int h, 31 | CF x, CF y) 32 | { 33 | CFA cf = (CFA) new_cf(sizeof(struct st_cf_arith)); 34 | if (cf == 0) return 0; 35 | 36 | cf->a = a; 37 | cf->b = b; 38 | cf->c = c; 39 | cf->d = d; 40 | cf->e = e; 41 | cf->f = f; 42 | cf->g = g; 43 | cf->h = h; 44 | 45 | cf->x = x; 46 | cf->x_done = 0; 47 | cf->y = y; 48 | cf->y_done = 0; 49 | 50 | cf->next = next_arith; 51 | 52 | return (CF)cf; 53 | } 54 | 55 | static int 56 | next_arith(CF cf) 57 | { 58 | int oops = 30; 59 | while (1) { 60 | #ifdef DEBUG_COEFFS 61 | fprintf(stderr, "I'm now %d %d %d %d / %d %d %d %d\n", 62 | cfa->a, cfa->b, cfa->c, cfa->d, 63 | cfa->e, cfa->f, cfa->g, cfa->h 64 | ); 65 | #endif 66 | if (cfa->e == 0 && cfa->f == 0 && cfa->g == 0 && cfa->h == 0) 67 | return C_INF; 68 | else { 69 | double 70 | b11 = bound(cfa->a, cfa->e), 71 | b01 = bound(cfa->c, cfa->g), 72 | b10 = bound(cfa->b, cfa->f), 73 | b00 = bound(cfa->d, cfa->h); 74 | int i11 = b11, i10 = b10, i01 = b01, i00 = b00; 75 | 76 | if (i11 == i10 && i10 == i01 && i01 == i00) { 77 | egest(cfa, i11); 78 | return i11; 79 | } else { 80 | double 81 | xw = MAX(IDIFF(b11, b01), IDIFF(b10, b00)), 82 | yw = MAX(IDIFF(b11, b10), IDIFF(b01, b00)); 83 | #ifdef DEBUG_BOUNDS 84 | fprintf(stderr, "bounds: %f %f %f %f\n", b00, b01, b10, b11); 85 | fprintf(stderr, "x diffs: %f %f\n", IDIFF(b11, b01), IDIFF(b10, b00)); 86 | fprintf(stderr, "y diffs: %f %f\n", IDIFF(b11, b10), IDIFF(b01, b00)); 87 | fprintf(stderr, "x bound = %f, y bound = %f\n", xw, yw); 88 | #endif 89 | 90 | if (xw > yw) { 91 | ingest_x(cfa); 92 | } else { 93 | ingest_y(cfa); 94 | } 95 | } 96 | } 97 | 98 | if (--oops < 1) { 99 | fprintf(stderr, "next_arith loop ran too many times\n"); 100 | exit(1); 101 | } 102 | } 103 | } 104 | 105 | float 106 | bound(int n, int d) 107 | { 108 | return d == 0 ? C_INF : (float)n/(float)d; 109 | } 110 | 111 | void 112 | egest(CFA cf, int q) 113 | { 114 | int a = cf->a, b = cf->b, c = cf->c, d = cf->d; 115 | 116 | cf->a = cf->e; 117 | cf->b = cf->f; 118 | cf->c = cf->g; 119 | cf->d = cf->h; 120 | 121 | cf->e = a - q*cf->e; 122 | cf->f = b - q*cf->f; 123 | cf->g = c - q*cf->g; 124 | cf->h = d - q*cf->h; 125 | 126 | #ifdef DEBUG_IO 127 | fprintf(stderr, "Egested %d\n", q); 128 | #endif 129 | } 130 | 131 | void 132 | ingest_x(CFA cf) 133 | { 134 | int p; 135 | 136 | p = next(cf->x); 137 | if (p == C_INF) { 138 | #ifdef DEBUG_IO 139 | fprintf(stderr, "Ingested oo from x\n"); 140 | #endif 141 | cf->x_done = 1; 142 | cf->c = cf->a; 143 | cf->d = cf->b; 144 | cf->g = cf->e; 145 | cf->h = cf->f; 146 | } else { 147 | int a = cf->a, b = cf->b, e = cf->e, f = cf->f; 148 | 149 | #ifdef DEBUG_IO 150 | fprintf(stderr, "Ingested %d from x\n", p); 151 | #endif 152 | 153 | cf->a = a*p + cf->c; 154 | cf->b = b*p + cf->d; 155 | cf->c = a; 156 | cf->d = b; 157 | 158 | cf->e = e*p + cf->g; 159 | cf->f = f*p + cf->h; 160 | cf->g = e; 161 | cf->h = f; 162 | } 163 | } 164 | 165 | 166 | void 167 | ingest_y(CFA cf) 168 | { 169 | int p; 170 | 171 | p = next(cf->y); 172 | if (p == C_INF) { 173 | #ifdef DEBUG_IO 174 | fprintf(stderr, "Ingested oo from y\n"); 175 | #endif 176 | cf->y_done = 1; 177 | cf->b = cf->a; 178 | cf->d = cf->c; 179 | cf->f = cf->e; 180 | cf->h = cf->g; 181 | } else { 182 | int a = cf->a, c = cf->c, e = cf->e, g = cf->g; 183 | 184 | #ifdef DEBUG_IO 185 | fprintf(stderr, "Ingested %d from y\n", p); 186 | #endif 187 | 188 | cf->a = a*p + cf->b; 189 | cf->b = a; 190 | cf->c = c*p + cf->d; 191 | cf->d = c; 192 | 193 | cf->e = e*p + cf->f; 194 | cf->f = e; 195 | cf->g = g*p + cf->h; 196 | cf->h = g; 197 | } 198 | } 199 | 200 | 201 | CF 202 | cadd(CF x, CF y) 203 | { 204 | return 205 | new_arith(0, 1, 1, 0, 206 | 0, 0, 0, 1, 207 | x, y); 208 | } 209 | 210 | CF 211 | csub(CF x, CF y) 212 | { 213 | return 214 | new_arith(0, 1, -1, 0, 215 | 0, 0, 0, 1, 216 | x, y); 217 | } 218 | 219 | CF 220 | cmul(CF x, CF y) 221 | { 222 | return 223 | new_arith(1, 0, 0, 0, 224 | 0, 0, 0, 1, 225 | x, y); 226 | } 227 | 228 | CF 229 | cdiv(CF x, CF y) 230 | { 231 | return 232 | new_arith(0, 1, 0, 0, 233 | 0, 0, 1, 0, 234 | x, y); 235 | } 236 | -------------------------------------------------------------------------------- /cf_arith.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_ARITH 3 | #define CF_H_ARITH 4 | 5 | #include "cf.h" 6 | 7 | CF new_arith(int, int, int, int, int, int, int, int, CF, CF); 8 | CF cadd(CF, CF); 9 | CF csub(CF, CF); 10 | CF cmul(CF, CF); 11 | CF cdiv(CF, CF); 12 | 13 | #endif 14 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /cf_between.c: -------------------------------------------------------------------------------- 1 | 2 | #include "cf_between.h" 3 | #include "cf_per.h" 4 | 5 | CF between(CF a, CF b) { 6 | 7 | } 8 | -------------------------------------------------------------------------------- /cf_between.h: -------------------------------------------------------------------------------- 1 | #ifndef CF_H_BETWEEN 2 | #define CF_H_BETWEEN 3 | 4 | #include "cf.h" 5 | 6 | CF between(CF, CF); 7 | 8 | #endif 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /cf_float.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "cf_float.h" 4 | #include 5 | #define EPSILON 1e-10 6 | 7 | 8 | typedef struct st_cf_float { 9 | BASE_CF; 10 | double d; 11 | } *CFF; 12 | 13 | #define cff ((CFF)cf) 14 | 15 | static int next_float(CF); 16 | 17 | CF 18 | new_float(double d) 19 | { 20 | CFF cf = (CFF) new_cf(sizeof(struct st_cf_float)); 21 | if (cf == 0) return 0; 22 | cf->d = d; 23 | cf->DONE = 0; 24 | cf->next = next_float; 25 | return (CF)cf; 26 | } 27 | 28 | static int 29 | next_float(CF cf) 30 | { 31 | int p; 32 | 33 | if (cff->DONE) return C_INF; 34 | 35 | p = (int)cff->d; 36 | #if 0 37 | printf("\n p=%d d=%lf diff=%.20f\n", 38 | p, cff->d, fabs(p - cff->d)); 39 | #endif 40 | if (fabs(p - cff->d) <= EPSILON) 41 | cff->DONE = 1; 42 | else 43 | cff->d = 1/(cff->d - p); 44 | 45 | return p; 46 | } 47 | 48 | -------------------------------------------------------------------------------- /cf_float.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_FLOAT 3 | #define CF_H_FLOAT 4 | 5 | #include "cf.h" 6 | 7 | CF new_float(double); 8 | 9 | #endif 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /cf_holo.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include "cf_holo.h" 5 | 6 | typedef struct st_cf_holo { 7 | BASE_CF; 8 | int a, b, c, d; 9 | CF x; 10 | char x_done; 11 | void (*ingest)(struct st_cf_holo *); 12 | void (*egest)(struct st_cf_holo *, int); 13 | } *CFH; 14 | 15 | #define cfh ((CFH)cf) 16 | 17 | static float bound(int, int); 18 | static void egest(CFH, int); 19 | static void egest_digit(CFH, int); 20 | static void ingest(CFH); 21 | static int next_holo(CF); 22 | 23 | CF 24 | new_holo(int a, int b, int c, int d, CF x) 25 | { 26 | CFH cf = (CFH) new_cf(sizeof(struct st_cf_holo)); 27 | if (cf == 0) return 0; 28 | 29 | cf->a = a; 30 | cf->b = b; 31 | cf->c = c; 32 | cf->d = d; 33 | 34 | cf->x = x; 35 | cf->x_done = 0; 36 | 37 | cf->next = next_holo; 38 | cf->ingest = ingest; 39 | cf->egest = egest; 40 | 41 | return (CF)cf; 42 | } 43 | 44 | CF 45 | new_dec(CF x) 46 | { 47 | CF cf = new_holo(1, 0, 0, 1, x); 48 | if (cf == 0) return 0; 49 | 50 | cfh->egest = egest_digit; 51 | 52 | return (CF)cf; 53 | } 54 | 55 | static int 56 | next_holo(CF cf) 57 | { 58 | int oops = 12; 59 | while (1) { 60 | #ifdef DEBUG 61 | fprintf(stderr, "I'm now %d %d / %d %d\n", cfh->a, cfh->b, cfh->c, cfh->d); 62 | #endif 63 | if (cfh->c == 0 && cfh->d == 0) 64 | return C_INF; 65 | else { 66 | float ub = bound(cfh->a, cfh->c), lb = bound(cfh->b, cfh->d); 67 | if ((int)ub == (int)lb) { 68 | cfh->egest(cfh, (int)ub); 69 | return (int)ub; 70 | } else { 71 | cfh->ingest(cfh); 72 | } 73 | } 74 | 75 | if (--oops < 1) { 76 | fprintf(stderr, "next_holo loop ran too many times\n"); 77 | exit(1); 78 | } 79 | } 80 | } 81 | 82 | float 83 | bound(int n, int d) 84 | { 85 | return d == 0 ? C_INF : (float)n/(float)d; 86 | } 87 | 88 | static void 89 | egest(CFH cf, int q) 90 | { 91 | int a = cf->a, b = cf->b; 92 | cf->a = cf->c; 93 | cf->b = cf->d; 94 | cf->c = a - q*cf->c; 95 | cf->d = b - q*cf->d; 96 | #ifdef DEBUG_IO 97 | fprintf(stderr, "Egested %d\n", q); 98 | #endif 99 | } 100 | 101 | static void 102 | egest_digit(CFH cf, int t) 103 | { 104 | cf->a = 10*(cf->a - cf->c * t); 105 | cf->b = 10*(cf->b - cf->d * t); 106 | #ifdef DEBUG_IO 107 | fprintf(stderr, "Egested %d\n", t); 108 | #endif 109 | } 110 | 111 | static void 112 | ingest(CFH cf) 113 | { 114 | int p; 115 | 116 | if (cf->x_done) return; /* err? */ 117 | 118 | p = next(cf->x); 119 | if (p == C_INF) { 120 | #ifdef DEBUG 121 | fprintf(stderr, "Ingested oo\n"); 122 | #endif 123 | cf->x_done = 1; 124 | cf->b = cf->a; 125 | cf->d = cf->c; 126 | } else { 127 | int a = cf->a, c = cf->c; 128 | 129 | #ifdef DEBUG 130 | fprintf(stderr, "Ingested %d\n", p); 131 | #endif 132 | 133 | cf->a = a*p + cf->b; 134 | cf->b = a; 135 | cf->c = c*p + cf->d; 136 | cf->d = c; 137 | } 138 | } 139 | 140 | -------------------------------------------------------------------------------- /cf_holo.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_HOLO 3 | #define CF_H_HOLO 4 | 5 | #include "cf.h" 6 | 7 | CF new_holo(int, int, int, int, CF); 8 | CF new_dec(CF); 9 | 10 | #endif 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /cf_it.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "cf_it.h" 4 | 5 | typedef struct st_cf_it { 6 | BASE_CF; 7 | unsigned n; 8 | int (*fun)(unsigned); 9 | } *CFI; 10 | #define cfi ((CFI)cf) 11 | 12 | static int next_it(CF); 13 | 14 | CF 15 | new_it(int (*f)(unsigned)) 16 | { 17 | CFI cf = (CFI) new_cf(sizeof(struct st_cf_it)); 18 | if (cf == 0) return 0; 19 | 20 | cf->n = 0; 21 | cf->fun = f; 22 | cf->next = next_it; 23 | 24 | return (CF)cf; 25 | } 26 | 27 | static int 28 | next_it(CF cf) 29 | { 30 | return cfi->fun(cfi->n++); 31 | } 32 | 33 | static int 34 | ef(unsigned n) 35 | { 36 | switch (n%3) { 37 | case 0: 38 | case 2: 39 | return 1; 40 | case 1: 41 | return 2*(n/3); 42 | } 43 | } 44 | 45 | CF 46 | e(void) 47 | { 48 | return new_it(ef); 49 | } 50 | 51 | -------------------------------------------------------------------------------- /cf_it.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_IT 3 | #define CF_H_IT 4 | 5 | #include "cf.h" 6 | 7 | CF new_it(int (*)(unsigned)); 8 | CF e(void); 9 | 10 | #endif 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /cf_per.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "cf_per.h" 4 | 5 | struct st_iarray { 6 | unsigned len; 7 | int a[1]; /* one or more */ 8 | }; 9 | 10 | static int next_periodic(CF); 11 | static void count_terms(va_list *, unsigned, struct st_iarray **); 12 | 13 | typedef struct st_cf_per { 14 | BASE_CF; 15 | struct st_iarray *iterms; /* initial terms */ 16 | struct st_iarray *terms; /* repeated terms */ 17 | unsigned pos; 18 | } *CFP; 19 | #define cfp ((CFP)cf) 20 | 21 | CF 22 | new_array(int a0,...) 23 | { 24 | va_list ap; 25 | struct st_iarray *inf = malloc(sizeof(struct st_iarray)), *a; 26 | CFP cf = (CFP) new_cf(sizeof(struct st_cf_per)); 27 | 28 | if (inf == 0 || cf == 0) return 0; 29 | 30 | va_start(ap, a0); 31 | count_terms(&ap, 1, &a); 32 | va_end(ap); 33 | a->a[0] = a0; 34 | 35 | cf->iterms = a; 36 | 37 | /* after the initial terms, produce infinity */ 38 | cf->terms = inf; 39 | cf->terms->len = 1; 40 | cf->terms->a[0] = C_INF; 41 | 42 | cf->pos = 0; 43 | cf->next = next_periodic; 44 | return (CF)cf; 45 | } 46 | 47 | CF 48 | new_periodic(int a0,...) 49 | { 50 | va_list ap; 51 | struct st_iarray *ia = malloc(sizeof(struct st_iarray)), *a; 52 | CFP cf = (CFP) new_cf(sizeof(struct st_cf_per)); 53 | 54 | if (ia == 0 || cf == 0) return 0; 55 | 56 | va_start(ap, a0); 57 | count_terms(&ap, 1, &a); 58 | va_end(ap); 59 | a->a[0] = a0; 60 | 61 | ia->len = 0; 62 | cf->iterms = ia; 63 | cf->terms = a; 64 | cf->pos = 0; 65 | cf->next = next_periodic; 66 | return (CF)cf; 67 | } 68 | 69 | CF 70 | new_periodic2(int a0,...) 71 | { 72 | va_list ap; 73 | struct st_iarray *ia, *a; 74 | CFP cf = (CFP) new_cf(sizeof(struct st_cf_per)); 75 | 76 | if (cf == 0) return 0; 77 | va_start(ap, a0); 78 | count_terms(&ap, 1, &ia); 79 | count_terms(&ap, 0, &a); 80 | va_end(ap); 81 | ia->a[0] = a0; 82 | 83 | cf->iterms = ia; 84 | cf->terms = a; 85 | cf->pos = 0; 86 | cf->next = next_periodic; 87 | return (CF)cf; 88 | } 89 | 90 | static void 91 | count_terms(va_list *ap, unsigned extra, struct st_iarray **ia) 92 | { 93 | unsigned count = 0, i; 94 | va_list ap_save; 95 | int nelts; 96 | 97 | va_copy(ap_save, *ap); 98 | 99 | while (va_arg(ap_save, int) != 0) count++; 100 | nelts = count+extra-1; 101 | if (nelts < 0) nelts = 0; 102 | #ifdef DEBUG_VARARGS 103 | fprintf(stderr, "count_terms counts %u plus %u extra - 1 = %d\n", 104 | count, extra, nelts); 105 | #endif 106 | 107 | *ia = malloc(sizeof(struct st_iarray) + nelts*sizeof(int)); 108 | if (*ia == 0) return; 109 | (*ia)->len = count+extra; 110 | 111 | count = extra; 112 | while ((i = va_arg(*ap, int)) != 0) { 113 | (*ia)->a[count++] = i; 114 | #ifdef DEBUG_VARARGS 115 | fprintf(stderr, "* copied %d\n", i); 116 | #endif 117 | } 118 | } 119 | 120 | 121 | static int 122 | next_periodic(CF cf) 123 | { 124 | unsigned n = cfp->pos++; 125 | if (cfp->pos == cfp->terms->len + cfp->iterms->len) 126 | cfp->pos -= cfp->terms->len; 127 | if (n >= cfp->iterms->len) 128 | return cfp->terms->a[n - cfp->iterms->len]; 129 | else 130 | return cfp->iterms->a[n]; 131 | } 132 | -------------------------------------------------------------------------------- /cf_per.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_PER 3 | #define CF_H_PER 4 | 5 | #include "cf.h" 6 | 7 | CF new_periodic(int, ...); 8 | CF new_periodic2(int, ...); 9 | CF new_array(int, ...); 10 | 11 | #endif 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /cf_rat.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include "cf_rat.h" 4 | #include 5 | 6 | typedef struct st_cf_rat { 7 | BASE_CF; 8 | int n, d; 9 | } *CFR; 10 | #define cfr ((CFR)cf) 11 | 12 | static int next_rat(CF); 13 | 14 | CF 15 | new_rat(int n, int d) 16 | { 17 | CFR cf = (CFR) new_cf(sizeof(struct st_cf_rat)); 18 | if (cf == 0) return 0; 19 | cf->n = n; 20 | cf->d = d; 21 | cf->next = next_rat; 22 | return (CF)cf; 23 | } 24 | 25 | CF 26 | new_rat_from_float(double f) 27 | { 28 | int d = 1; 29 | double of = f; 30 | 31 | while (f != rint(f) && (int)(f*2) >= 0 && d < 2*d) { 32 | f *= 2; 33 | d <<= 1; 34 | #ifdef DEBUG 35 | printf("%f => %f / %d\n", of, f, d); 36 | #endif 37 | } 38 | #ifdef DEBUG 39 | printf("%f => %d / %d\n", of, (int)(f+0.5), d); 40 | #endif 41 | return new_rat((int)(f+0.5), d); 42 | } 43 | 44 | static int 45 | next_rat(CF cf) 46 | { 47 | int p, den = cfr->d; 48 | 49 | if (den == 0) return C_INF; 50 | 51 | p = cfr->n / den; /* integer division */ 52 | cfr->d = cfr->n - p * den; 53 | cfr->n = den; 54 | return p; 55 | } 56 | 57 | -------------------------------------------------------------------------------- /cf_rat.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef CF_H_RAT 3 | #define CF_H_RAT 4 | 5 | #include "cf.h" 6 | 7 | CF new_rat(int, int); 8 | CF new_rat_from_float(double) ; 9 | 10 | #endif 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | 2 | #include "cf_rat.h" 3 | #include "cf_float.h" 4 | #include "cf_holo.h" 5 | #include "cf_arith.h" 6 | #include "cf_it.h" 7 | #include 8 | #include 9 | #include 10 | #define STREQ(a,b) (strcmp((a),(b)) == 0) 11 | 12 | int 13 | main(int argc, char **argv) 14 | { 15 | int n, d; 16 | double f; 17 | CF cf; 18 | 19 | switch(argc) { 20 | CF cfx, cfy; 21 | 22 | case 2: 23 | if (STREQ(argv[1], "e")) 24 | cf = new_dec(e()); 25 | else { 26 | f = atof(argv[1]); 27 | cf = new_rat_from_float(f); 28 | } 29 | break; 30 | 31 | case 3: 32 | if (STREQ(argv[1], "->d")) { 33 | f = atof(argv[2]); 34 | cfx = new_rat_from_float(f); 35 | cf = new_dec(cfx); 36 | } else { 37 | n = atoi(argv[1]); 38 | d = atoi(argv[2]); 39 | cf = new_rat(n, d); 40 | } 41 | break; 42 | 43 | case 4: 44 | cfx = new_rat_from_float(atof(argv[1])); 45 | cfy = new_rat_from_float(atof(argv[3])); 46 | 47 | switch (argv[2][0]) { 48 | case '+': cf = cadd(cfx, cfy); break; 49 | case '-': cf = csub(cfx, cfy); break; 50 | case '*': 51 | case 'x': cf = cmul(cfx, cfy); break; 52 | case '/': cf = cdiv(cfx, cfy); break; 53 | default: 54 | fprintf(stderr, "Unknown operator '%c'; use + - x /\n", argv[2][0]); 55 | return 1; 56 | } 57 | break; 58 | 59 | case 6: 60 | f = atof(argv[5]); 61 | cfx = new_rat_from_float(f); 62 | cf = new_holo(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), cfx); 63 | break; 64 | 65 | case 11: 66 | cfx = new_rat_from_float(atof(argv[9])); 67 | cfy = new_rat_from_float(atof(argv[10])); 68 | cf = new_arith(atoi(argv[1]), atoi(argv[2]), atoi(argv[3]), atoi(argv[4]), 69 | atoi(argv[5]), atoi(argv[6]), atoi(argv[7]), atoi(argv[8]), 70 | cfx, cfy); 71 | break; 72 | 73 | default: 74 | fprintf(stderr, "Usage:\t%1$s num den\n\t%1$s real\n\t%1$s a b c d real\n\t%1$s a b c d e f g h real real\n\t%1$s real +-x/ real\n", argv[0]); 75 | return 1; 76 | } 77 | 78 | print_cf(cf); 79 | return 0; 80 | } 81 | -------------------------------------------------------------------------------- /man/demo.1: -------------------------------------------------------------------------------- 1 | .TH cf-demo 1 2 | .SH NAME 3 | cf-demo \- demonstration of continued fraction library 4 | .SH SYNOPSIS 5 | cf-demo e # calculate decimal expansion of \fIe\fR 6 | cf-demo \fIx\fR # calculate expansion of real number \fIx\fR 7 | cf-demo \fIn d\fR # calculate expansion of \fIn/d\fR 8 | cf-demo \fIa b c d x\fR # calculate expansion of \fI(ax+b)/(cd+x)\fR 9 | cf-demo \fIa b c d e f h x y\fR # calculate expansion of \fI(axy+bx+cy+d)/(exy+fx+gy+h)\fR 10 | cf-demo \fIx\fR + \fIy\fR # calculate expansion of \fIx\fR + \fIy\fR 11 | cf-demo \fIx\fR - \fIy\fR # calculate expansion of \fIx\fR - \fIy\fR 12 | cf-demo \fIx\fR x \fIy\fR # calculate expansion of \fIx\fR * \fIy\fR 13 | cf-demo \fIx\fR / \fIy\fR # calculate expansion of \fIx\fR / \fIy\fR 14 | cf-demo '->d' \fIx\fR # calculate decimal expansion of \fIx\fR 15 | 16 | .SH DESCRIPTION 17 | 18 | .B cf-demo 19 | is a demonstration program for the 20 | .BF cf 21 | continued-fraction calculation library. 22 | .B demo 23 | can be invoked in several ways to exercise the various features of 24 | .BR cf . 25 | 26 | .IP \fBdemo\ \fIn\ d\fR 27 | calculates and prints the continued-fraction expansion of the rational 28 | number 29 | .IR n / d 30 | where 31 | .I n 32 | and 33 | .I d 34 | are integers. The 35 | .B cf 36 | function 37 | .IR new_rat () 38 | is used to manufacture the continued-fraction object, and then 39 | .IR print_cf () 40 | is used to print the terms of the continued fraction. 41 | 42 | .IP \fBdemo\ \fIx\fR 43 | uses 44 | .IR new_rat_from_float () 45 | to build a continued fraction with the value of 46 | .IR x , 47 | which is a floating-point number in the usual format. 48 | The terms of the continued fraction are then printed. 49 | 50 | .IP \fBdemo\ \fIa\ b\ c\ d\ x\fR 51 | first uses 52 | .IR new_rat_from_float () 53 | to convert 54 | .I x 55 | to a continued fraction, and then 56 | .IR new_holo () 57 | to calculate a continued-fraction expansion for the value 58 | .IR ax + b 59 | / 60 | .IR cx + d . 61 | The terms of this latter continued fraction are then printed. 62 | .I x 63 | should be in floating-point format; 64 | .IR a ,\ b ,\ c ,\ and\ d 65 | should be integers. 66 | 67 | .IP \fBdemo\ \fIa\ b\ c\ d\ e\ f\ g\ h\ x\ y\fR 68 | uses 69 | .IR new_rat_from_float () 70 | to convert 71 | .IR x and y 72 | to continued fractions, and then 73 | .IR new_arith () 74 | to calculate a continued-fraction expansion for the value 75 | .IR axy + bx + cy + d 76 | / 77 | .IR exy + fx + gy + h . 78 | The terms of this latter continued fraction are then printed. 79 | .I x 80 | and 81 | .I y 82 | should be in floating-point format; 83 | .IR a ,\ b ,\ c ,\ d ,\ e ,\ f ,\ g ,\ and\ h 84 | should be integers. 85 | 86 | .IP \fBdemo\ \fIx\ \fR+\ \fIy\fR 87 | .IP \fBdemo\ \fIx\ \fR-\ \fIy\fR 88 | .IP \fBdemo\ \fIx\ \fR*\ \fIy\fR 89 | .IP \fBdemo\ \fIx\ \fR/\ \fIy\fR 90 | 91 | .I x 92 | and 93 | .I y 94 | are real numbers in floating-point format. 95 | .IR new_rat_from_float () 96 | is called to convert them to continued-fraction representation, and 97 | then 98 | .IR new_arith () 99 | is used to perform the indicated operation (addition, subtraction, 100 | multiplication, or division) is performed on the two values. The 101 | terms of the result then printed. 102 | 103 | .P 104 | Note that '*' is special in the shell and will need to be quoted. The 105 | program will accept the letter "x" as a synonym. 106 | 107 | .IP \fBdemo\ \fRe 108 | 109 | This calculates and prints the decimal value of \fIe\fR (2.71818...) 110 | from the continued fraction representation. Specifically, the 111 | continued fraction [2; 1, 2, 1, 1, 4, 1, 1, 6, 1, 1, 8, 1, ...] is 112 | contstructed, and then 113 | .IR new_dec () 114 | is used to convert it to a decimal. 115 | 116 | .IP \fBdemo\ \fR'->d'\ \fIx\fR 117 | 118 | .I x 119 | is a real number as above. The real number is converted to a 120 | continued fraction, using 121 | .IR new_rat_from_float (). 122 | The continued fraction is then converted back to a sequence of 123 | decimal digits, using 124 | .IR new_dec (), 125 | and the decimal digits are displayed. 126 | 127 | .SH AUTHOR 128 | 129 | Mark Jason Dominus (mjd@plover.com) 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /man/libcf.3: -------------------------------------------------------------------------------- 1 | 2 | libcf is a collection of related classes for performing arithmetic on 3 | continued fractions. It is intended primarily as a demonstration of 4 | Gosper's algorithms, not as a high-quality numeric calculation 5 | library. 6 | 7 | #include "cf.h" 8 | 9 | CF continued_fraction = new_cf(s); 10 | int term = next(continued_fraction); 11 | 12 | print_cf(continued_fraction); 13 | fprint_cf(stream, continued_fraction); 14 | 15 | The abstract base class is "CF". new_cf(s) allocates a continued 16 | fraction object of size s bytes. Since CF is abstract, the object 17 | returned by new_cf() is not actually usable without additional work. 18 | It is provided as a convenience function for subclasses; see 19 | SUBCLASSING below. However, any function that works on a generic CF 20 | object will also work on an object from one of its subclasses. 21 | 22 | next() accepts a continued fraction object and returns its next term, 23 | modifying the object in the process. 24 | 25 | fprint_cf() accepts a standard I/O stream and a continued fraction 26 | object and prints out all the terms of the ofraction to the specified 27 | stream. print_cf(x) is equivalent to fprint_cf(stdout, x). 28 | 29 | 30 | #include "cf_rat.h" 31 | 32 | CF cf1 = new_rat(num, den); 33 | CF cf2 = new_rat_from_float(real); 34 | 35 | These functions generate finite continued fractions that represent 36 | specific rational numbers. new_rat() accepts an integer numerator and 37 | denominator. new_rat_from_float accepts a floating point number, 38 | which is interpreted as a rational with a power-of-2 denominator. 39 | (For example, .333333333333333333 is interpreted as 357913941 / 40 | 1073741824.) The functions return continued fraction objects. These 41 | objects can be used with any function that accepts CFs, such as next(). 42 | 43 | #include "cf_float.h" 44 | 45 | CF cf = new_float(real); 46 | 47 | This function generates a CF object that represents the specified real 48 | number, which is given as a floating-point value. Unlike 49 | new_rat_from_float(), the value is not immediately converted to a 50 | rational number. When computing the terms of its continued-fraction 51 | expansion, floating-point arithmetic is used, with all its usual 52 | roundoff problems. 53 | 54 | #include "cf_holo.h" 55 | 56 | CF cf = new_holo(a, b, c, d, x); 57 | CF cf = new_dec(x); 58 | 59 | Given integers a, b, c, and d, and a continued fraction object x, 60 | new_holo() returns a new continued fraction object that represents the 61 | value (ax+b)/(cx + d). new_dec() takes a CF object x and returns 62 | something that appears to be a CF object, but which produces decimal 63 | digits instead of CF terms. 64 | 65 | #include "cf_arith.h" 66 | 67 | CF cf = new_arith(a, b, c, d, 68 | e, f, g, h, 69 | x, y); 70 | 71 | CF cf = cadd(x, y); 72 | CF cf = csub(x, y); 73 | CF cf = cmul(x, y); 74 | CF cf = cdiv(x, y); 75 | 76 | Given integers a .. h and continued fraction objects x and y, 77 | new_arith() returns a new continued fraction object that represents 78 | the value (axy+bx+cy+d)/(exy+fx+gy+h). 79 | 80 | Given continued fraction objects x and y, cadd(), csub(), cmul(), and 81 | cdiv() return x+y, x-y, x*y, and x/y, respectively. 82 | 83 | #include "cf_it.h" 84 | 85 | int some_fun(unsigned); 86 | CF cf = new_it(some_fun); 87 | CF E = e(); 88 | 89 | If some_fun() is a function that takes an unsigned int and returns an 90 | integer, new_it(some_fun) returns a CF object whose terms are 91 | 92 | some_fun(0), some_fun(1), some_fun(2), ... 93 | 94 | The function e() returns a CF that represents the number e (2.71828...) 95 | 96 | Todo: #include "cf_per.h" 97 | 98 | 99 | 100 | SUBCLASSING 101 | 102 | We'll create a new subclass of CF, called "cf_aseq", to represent 103 | continued fractions whose terms are arithmetic sequences. First we 104 | need an interface header, "cf_aseq.h". The public interface of our 105 | new class is a single function, new_aseq(), which takes two integers, 106 | say a and d, and returns a CF object whose terms will be a, a+d, a+2d, 107 | ... . The interface header only needs to provide a declaration of 108 | this function: 109 | 110 | #ifndef CF_H_ASEQ 111 | #define CF_H_ASEQ 112 | 113 | #include "cf.h" 114 | 115 | CF new_aseq(int, int); 116 | 117 | #endif 118 | 119 | The implementation must define this function, and also the structure 120 | that actually represents a cf_aseq value. It starts like this: 121 | 122 | #include "cf_aseq.h" 123 | 124 | typedef struct st_cf_aseq { 125 | BASE_CF; 126 | int a, d; 127 | unsigned n; 128 | } *CF_ASEQ; 129 | 130 | static int next_aseq(CF); 131 | 132 | BASE_CF is a macro that is provided by "cf.h". It defines the 133 | structure members that are required to be present at the beginning of 134 | every CF object. a, d, and n, however, belong to us. We also declare 135 | a private function, next_aseq(), which we'll see shortly. 136 | 137 | Now we must provide the promised new_aseq() function: 138 | 139 | CF 140 | new_aseq(int a, int d) 141 | { 142 | CF_ASEQ cf = (CF_ASEQ) new_cf(sizeof(struct st_cf_aseq)); 143 | if (cf == 0) return 0; 144 | 145 | cf->a = a; 146 | cf->d = d; 147 | cf->n = 0; 148 | 149 | cf->next = next_aseq; 150 | return (CF) cf; 151 | } 152 | 153 | The function allocates a new CF object using new_cf; we pass it the 154 | size of the structure we want to allocate. Then the function copies 155 | the a and d parameters into the new object. The member n will be a 156 | counter that records what term will be next; initially, it is 0. 157 | cf->next is a member provided in BASE_CF; it's a pointer to a callback 158 | function whose job is to return the next term of the CF each time it's 159 | called. We must now implement next_aseq: 160 | 161 | static int 162 | next_aseq(CF cf) 163 | { 164 | CF_ASEQ cfa = cf; 165 | return cfa->a + cfa->d * cfa->n++; 166 | } 167 | 168 | Since the function's argument is a generic CF, we allocate a variable 169 | "cfa" to serve as a CF_ASEQ-type alias for it. This allows us to 170 | access the a, d, and n fields, which aren't available via the generic 171 | version of the object. The function calculates the appropriate term, 172 | incrementing the n member along the way, and returns the appropriate 173 | value. 174 | 175 | An alternative formulation avoids the alias variable by using casts 176 | instead: 177 | 178 | #define cfa ((CF_ASEQ)cf) 179 | 180 | static int 181 | next_aseq(CF cf) 182 | { 183 | return cfa->a + cfa->d * cfa->n++; 184 | } 185 | 186 | 187 | Now let's see another example. We'll call it CF_TRUNC. It will take 188 | as input a CF object and return another CF whose terms are the same, 189 | except that it stops prematurely. 190 | 191 | Here's cf_trunc.h: 192 | 193 | #ifndef CF_H_TRUNC 194 | #define CF_H_TRUNC 195 | 196 | #include "cf.h" 197 | 198 | CF new_trunc(CF, unsigned); 199 | 200 | #endif 201 | 202 | new_trunc() will get two arguments: the input CF, and an integer n 203 | that says to truncate the input after n terms. 204 | 205 | Here's the implementation: 206 | 207 | #include "cf_trunc.h" 208 | 209 | typedef struct st_cf_trunc { 210 | BASE_CF; 211 | CF x; 212 | char x_done; 213 | unsigned n; 214 | } *CF_TRUNC; 215 | 216 | static int next_trunc(CF); 217 | 218 | CF 219 | new_aseq(CF x, unsigned n) 220 | { 221 | CF_TRUNC cf = (CF_TRUNC) new_cf(sizeof(struct st_cf_trunc)); 222 | if (cf == 0) return 0; 223 | 224 | cf->x = x; 225 | cf->x_done = 0; 226 | cf->n = n; 227 | 228 | cf->next = next_trunc; 229 | return (CF) cf; 230 | } 231 | 232 | #define cft ((CF_TRUNC)cf) 233 | 234 | int 235 | next_trunc(CF cf) 236 | { 237 | if (cft->x_done) return C_INF; 238 | else if (cft->n == 0) return C_INF; 239 | else { 240 | int p = next(cft->x); 241 | if (p == C_INF) cft->x_done = 1; 242 | cft->n -= 1; 243 | return P; 244 | } 245 | } 246 | 247 | The only new machinery here is in next_trunc(). A CF can indicate 248 | that it has no more terms by returning the special constant C_INF, 249 | defined in cf.h. Our CF_TRUNC object will do this if its counter 250 | indicates that it has already delivered the appropriate number of 251 | terms (cft->n == 0). It also contains a flag, x_done, that records 252 | whether its input CF has been exhausted; it returns C_INF to 253 | indicate exhaustion in this case as well. 254 | 255 | If the input is not already known to be exhausted, next_trunc() uses 256 | the next() function provided by cf.h to read the next term from the 257 | input CF. If this next term is C_INF, indicating that no more data 258 | is available, it sets the x_done flag; it then decrements its counter 259 | and returns the term. 260 | 261 | 262 | -------------------------------------------------------------------------------- /surd.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include "cf.h" 5 | #include "cf_per.h" 6 | #include "cf_arith.h" 7 | 8 | int main(void) { 9 | CF sqrt2, sqrt3; 10 | CF sum; 11 | 12 | sqrt2 = new_periodic2(1, 0, 2, 0); 13 | sqrt3 = new_periodic2(1, 0, 1, 2, 0); 14 | sum = cadd(sqrt2, sqrt3); 15 | while (1) { 16 | unsigned i; 17 | int c; 18 | 19 | for (i=0; i < 20; i++) { 20 | int n; 21 | n = next(sum); 22 | if (n == C_INF) return; 23 | printf("%d%c", n, i==19 ? '\n' : ' '); 24 | } 25 | c = getchar(); 26 | if (c == EOF) break; 27 | } 28 | return; 29 | } 30 | -------------------------------------------------------------------------------- /surd2.c: -------------------------------------------------------------------------------- 1 | 2 | 3 | #include 4 | #include "cf.h" 5 | #include "cf_per.h" 6 | #include "cf_arith.h" 7 | 8 | int main(void) { 9 | CF phi, sqrt2p1; 10 | CF sum; 11 | 12 | phi= new_periodic(1, 0); 13 | sqrt2p1 = new_periodic(2, 0); 14 | sum = cadd(sqrt2p1, phi); 15 | while (1) { 16 | unsigned i; 17 | int c; 18 | 19 | for (i=0; i < 20; i++) { 20 | int n; 21 | n = next(sum); 22 | if (n == C_INF) return; 23 | printf("%d%c", n, i==19 ? '\n' : ' '); 24 | } 25 | c = getchar(); 26 | if (c == EOF) break; 27 | } 28 | return; 29 | } 30 | -------------------------------------------------------------------------------- /t/appendtest.c: -------------------------------------------------------------------------------- 1 | 2 | #include "../cf_per.h" 3 | #include "../cf_append.h" 4 | 5 | int main(void) 6 | { 7 | { 8 | CF cf123 = new_array(1, 2, 3, 0); 9 | CF cf1234 = append1(cf123, 4); 10 | CF cf12345 = append1(cf1234, 5); 11 | print_cf(cf12345); 12 | } 13 | { 14 | CF cf123 = new_array(1, 2, 3, 0); 15 | CF cf1234 = new_array(1, 2, 3, 4, 0); 16 | CF cf1234123 = CF_appendcf(cf1234, cf123, (CF)0); 17 | print_cf(cf1234123); 18 | } 19 | { 20 | CF cf123a = new_array(1, 2, 3, 0); 21 | CF cf123b = new_array(1, 2, 3, 0); 22 | CF cf1234 = new_array(1, 2, 3, 4, 0); 23 | CF cf1231234123 = CF_appendcf(cf123a, cf1234, cf123b, (CF)0); 24 | print_cf(cf1231234123); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /t/arraytest.c: -------------------------------------------------------------------------------- 1 | 2 | #include "../cf_per.h" 3 | 4 | int main(void) 5 | { 6 | CF cf123 = new_array(1, 2, 3, 0); 7 | print_cf(cf123); 8 | } 9 | --------------------------------------------------------------------------------