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