multiply.w
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:10k
源码类别:

通讯编程

开发平台:

Visual C++

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