1% This file is part of the Stanford GraphBase (c) Stanford University 1993
2@i boilerplate.w %<< legal stuff: PLEASE READ IT BEFORE MAKING ANY CHANGES!
3@i gb_types.w
4
5\def\title{MULTIPLY}
6
7\prerequisite{GB\_\,GATES}
8@* Introduction. This demonstration program uses graphs
9constructed by the |prod| procedure in the {\sc GB\_\,GATES} module to produce
10an interactive program called \.{multiply}, which multiplies and divides
11small numbers the slow way---by simulating the behavior of
12a logical circuit, one gate at a time.
13
14The program assumes that \UNIX/ conventions are being used. Some code in
15sections listed under `\UNIX/ dependencies' in the index might need to change
16if this program is ported to other operating systems.
17
18\def\<#1>{$\langle${\rm#1}$\rangle$}
19To run the program under \UNIX/, say `\.{multiply} $m$ $n$ [|seed|]', where
20$m$ and $n$ are the sizes of the numbers to be multiplied, in bits,
21and where |seed| is given if and only if you want the multiplier
22to be a special-purpose circuit for multiplying a given $m$-bit
23number by a randomly chosen $n$-bit constant.
24
25The program will prompt you for two numbers (or for just one, if the
26random constant option has been selected), and it will use the gate
27network to compute their product. Then it will ask for more input, and so on.
28
29@ Here is the general layout of this program, as seen by the \CEE/ compiler:
30@^UNIX dependencies@>
31
32@p
33#include "gb_graph.h" /* the standard GraphBase data structures */
34#include "gb_gates.h" /* routines for gate graphs */
35@h@#
36@<Global variables@>@;
37@<Handy subroutines@>@;
38main(argc,argv)
39  int argc; /* the number of command-line arguments */
40  char *argv[]; /* an array of strings containing those arguments */
41{
42  @<Declare variables that ought to be in registers@>;
43  @<Obtain |m|, |n|, and optional |seed| from the command line@>;
44  @<Make sure |m| and |n| are valid; generate the |prod| graph |g|@>;
45  if (seed<0) /* no seed given */
46   printf("Here I am, ready to multiply %ld-bit numbers by %ld-bit numbers.\n",
47       m,n);
48  else {
49    g=partial_gates(g,m,0L,seed,buffer);
50    if (g) {
51      @<Set |y| to the decimal value of the second input@>;
52      printf("OK, I'm ready to multiply any %ld-bit number by %s.\n",m,y);
53    }@+else { /* there was enough memory to make the original |g|, but
54                not enough to reduce it; this probably can't happen,
55                but who knows? */
56      printf("Sorry, I couldn't process the graph (trouble code %ld)!\n",
57         panic_code);
58      return -9;
59    }
60  }
61  printf("(I'm simulating a logic circuit with %ld gates, depth %ld.)\n",
62     g->n,depth(g));
63  while(1) {
64    @<Prompt for one or two numbers; |break| if unsuccessful@>;
65    @<Use the network to compute the product@>;
66    printf("%sx%s=%s%s.\n",x,y,(strlen(x)+strlen(y)>35?"\n ":""),z);
67  }
68  return 0; /* normal exit */
69}
70
71@ @<Make sure |m| and |n| are valid; generate the |prod| graph |g|@>=
72if (m<2) m=2;
73if (n<2) n=2;
74if (m>999 || n>999) {
75  printf("Sorry, I'm set up only for precision less than 1000 bits.\n");
76  return -1;
77}
78if ((g=prod(m,n))==NULL) {
79  printf("Sorry, I couldn't generate the graph (not enough memory for %s)!\n",
80    panic_code==no_room? "the gates": panic_code==alloc_fault? "the wires":
81     "local optimization");
82  return -3;
83}
84
85@ To figure the maximum length of strings |x| and |y|, we note that
86$2^{999}\approx5.4\times10^{300}$.
87
88@<Glob...@>=
89Graph *g; /* graph that defines a logical network for multiplication */
90long m,n; /* length of binary numbers to be multiplied */
91long seed; /* optional seed value, or $-1$ */
92char x[302], y[302], z[603]; /* input and output numbers, as decimal strings */
93char buffer[2000]; /* workspace for communication between routines */
94
95@ @<Declare variables...@>=
96register char *p,*q,*r; /* pointers for string manipulation */
97register long a,b; /* amounts being carried over while doing radix conversion */
98
99@ @<Obtain |m|, |n|, and...@>=
100@^UNIX dependencies@>
101if (argc<3 || argc>4 || sscanf(argv[1],"%ld",&m)!=1 ||
102              sscanf(argv[2],"%ld",&n)!=1) {
103  fprintf(stderr,"Usage: %s m n [seed]\n",argv[0]);
104  return -2;
105}
106if (m<0) m=-m; /* maybe the user attached |'-'| to the argument */
107if (n<0) n=-n;
108seed=-1;
109if (argc==4 && sscanf(argv[3],"%ld",&seed)==1 && seed<0)
110  seed=-seed;
111
112@ This program may not be user-friendly, but at least it is polite.
113
114@d prompt(s)
115    {@+printf(s);@+fflush(stdout); /* make sure the user sees the prompt */
116      if (fgets(buffer,999,stdin)==NULL) break;@+}
117@d retry(s,t)
118    {@+printf(s);@+goto t;@+}
119
120@<Prompt...@>=
121step1: prompt("\nNumber, please? ");
122for (p=buffer;*p=='0';p++) ; /* bypass leading zeroes */
123if (*p=='\n') {
124  if (p>buffer) p--; /* zero is acceptable */
125  else break; /* empty input terminates the run */
126}
127for (q=p;*q>='0' && *q<='9';q++) ; /* check for digits */
128if (*q!='\n') retry(
129    "Excuse me... I'm looking for a nonnegative sequence of decimal digits.",
130      step1);
131*q=0;
132if (strlen(p)>301)
133  retry("Sorry, that's too big.",step1);
134strcpy(x,p);
135if (seed<0) {
136  @<Do the same thing for |y| instead of |x|@>;
137}
138
139@ @<Do the same...@>=
140step2: prompt("Another? ");
141for (p=buffer;*p=='0';p++) ; /* bypass leading zeroes */
142if (*p=='\n') {
143  if (p>buffer) p--; /* zero is acceptable */
144  else break; /* empty input terminates the run */
145}
146for (q=p;*q>='0' && *q<='9';q++) ; /* check for digits */
147if (*q!='\n') retry(
148    "Excuse me... I'm looking for a nonnegative sequence of decimal digits.",
149      step2);
150*q=0;
151if (strlen(p)>301)
152  retry("Sorry, that's too big.",step2);
153strcpy(y,p);
154
155@ The binary value chosen at random by |partial_gates| appears as a
156string of 0s and 1s in |buffer|, in little-endian order. We compute
157the corresponding decimal value by repeated doubling.
158
159If the value turns out to be zero, the whole network will have collapsed.
160Otherwise, however, the |m| inputs from the first operand
161will all remain present, because they all affect the output.
162
163@<Set |y| to the decimal value of the second input@>=
164*y='0';@+*(y+1)=0; /* now |y| is |"0"| */
165for (r=buffer+strlen(buffer)-1;r>=buffer;r--) {
166    /* we will set $y=2y+t$ where $t$ is the next bit, |*r| */
167  if (*y>='5') a=0,p=y;
168  else a=*y-'0',p=y+1;
169  for (q=y;*p;a=b,p++,q++) {
170    if (*p>='5') {
171       b=*p-'5';
172       *q=2*a+'1';
173     }@+else {
174       b=*p-'0';
175       *q=2*a+'0';
176     }
177  }
178  if (*r=='1') *q=2*a+'1';
179  else *q=2*a+'0';
180  *++q=0; /* terminate the string */
181}
182if (strcmp(y,"0")==0) {
183  printf("Please try another seed value; %d makes the answer zero!\n",seed);
184  return(-5);
185}
186
187@* Using the network. The reader of the code in the previous section
188will have noticed that we are representing high-precision decimal
189numbers as strings. We might as well do that, since the only
190operations we need to perform on them are input, output, doubling, and
191halving. In fact, arithmetic on strings is kind of fun, if you like
192that sort of thing.
193
194Here is a subroutine that converts a decimal string to a binary string.
195The decimal string is big-endian as usual, but the binary string is
196little-endian. The decimal string is decimated in the process; it
197should end up empty, unless the original value was too big.
198
199@<Handy subroutines@>=
200decimal_to_binary(x,s,n)
201  char *x; /* decimal string */
202  char *s; /* binary string */
203  long n; /* length of |s| */
204{@+register long k;
205  register char *p,*q; /* pointers for string manipulation */
206  register long r; /* remainder */
207  for (k=0;k<n;k++,s++) {
208    if (*x==0) *s='0';
209    else { /* we will divide |x| by 2 */
210      if (*x>'1') p=x,r=0;
211      else p=x+1,r=*x-'0';
212      for (q=x;*p;p++,q++) {
213        r=10*r+*p-'0';
214        *q=(r>>1)+'0';
215        r=r&1;
216      }
217      *q=0; /* terminate string |x| */
218      *s='0'+r;
219    }
220  }
221  *s=0; /* terminate the output string */
222}
223
224@ @<Use the network to compute the product@>=
225strcpy(z,x);
226decimal_to_binary(z,buffer,m);
227if (*z) {
228  printf("(Sorry, %s has more than %ld bits.)\n",x,m);
229  continue;
230}
231if (seed<0) {
232  strcpy(z,y);
233  decimal_to_binary(z,buffer+m,n);
234  if (*z) {
235    printf("(Sorry, %s has more than %ld bits.)\n",y,n);
236    continue;
237  }
238}
239if (gate_eval(g,buffer,buffer)<0) {
240  printf("??? An internal error occurred!");
241  return 666; /* this can't happen */
242}
243@<Convert the binary number in |buffer| to the decimal string |z|@>;
244
245@ The remaining task is almost identical to what we needed to do
246when computing the value of |y| after a random seed was specified.
247But this time the binary number in |buffer| is big-endian.
248
249@<Convert the binary number in |buffer| to the decimal string |z|@>=
250*z='0';@+*(z+1)=0;
251for (r=buffer;*r;r++) {
252    /* we'll set $z=2z+t$ where $t$ is the next bit, |*r| */
253  if (*z>='5') a=0,p=z;
254  else a=*z-'0',p=z+1;
255  for (q=z;*p;a=b,p++,q++) {
256    if (*p>='5') {
257       b=*p-'5';
258       *q=2*a+'1';
259     }@+else {
260       b=*p-'0';
261       *q=2*a+'0';
262     }
263  }
264  if (*r=='1') *q=2*a+'1';
265  else *q=2*a+'0';
266  *++q=0; /* terminate the string */
267}
268
269@* Calculating the depth. The depth of a gate network produced by {\sc
270GB\_\,GATES} is easily discovered by making one pass over the
271vertices.  An input gate or a constant has depth~0; every other gate
272has depth one greater than the maximum of its inputs.
273
274This routine is more general than it needs to be for the circuits output
275by |prod|. The result of a latch is considered to have depth~0.
276
277Utility field |u.I| is set to the depth of each individual gate.
278
279@d dp u.I
280
281@<Handy...@>=
282long depth(g)
283  Graph *g; /* graph with gates as vertices */
284{@+register Vertex *v; /* the current vertex of interest */
285  register Arc *a; /* the current arc of interest */
286  long d; /* depth of current vertex */
287  if (!g) return -1; /* no graph supplied! */
288  for (v=g->vertices; v<g->vertices+g->n; v++) {
289    switch (v->typ) { /* branch on type of gate */
290    case 'I': case 'L': case 'C': v->dp=0;@+break;
291    default: @<Set |d| to the maximum depth of an operand of |v|@>;
292      v->dp=1+d;
293    }
294  }
295  @<Set |d| to the maximum depth of an output of |g|@>;
296  return d;
297}
298
299@ @<Set |d| to the maximum depth of an operand of |v|@>=
300d=0;
301for (a=v->arcs; a; a=a->next)
302  if (a->tip->dp>d) d=a->tip->dp;
303
304@ @<Set |d| to the maximum depth of an output of |g|@>=
305d=0;
306for (a=g->outs; a; a=a->next)
307  if (!is_boolean(a->tip) && a->tip->dp>d) d=a->tip->dp;
308
309@* Index. Finally, here's a list that shows where the identifiers of this
310program are defined and used.
311