5761221 [rkeene@sledge /home/rkeene/devel/old/bc-dos/dc]$ cat -n numeric.c
  1 /* 
  2  * interface dc to the bc numeric routines
  3  *
  4  * Copyright (C) 1994, 1997, 1998 Free Software Foundation, Inc.
  5  *
  6  * This program is free software; you can redistribute it and/or modify
  7  * it under the terms of the GNU General Public License as published by
  8  * the Free Software Foundation; either version 2, or (at your option)
  9  * any later version.
 10  *
 11  * This program is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 14  * GNU General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU General Public License
 17  * along with this program; if not, you can either send email to this
 18  * program's author (see below) or write to: The Free Software Foundation,
 19  * Inc.; 675 Mass Ave. Cambridge, MA 02139, USA.
 20  */
 21 
 22 /* This should be the only module that knows the internals of type dc_num */
 23 /* In this particular implementation we just slather out some glue and
 24  * make use of bc's numeric routines.
 25  */
 26 
 27 #include "config.h"
 28 
 29 #include <stdio.h>
 30 #include <ctype.h>
 31 #ifdef HAVE_LIMITS_H
 32 # include <limits.h>
 33 #else
 34 # define UCHAR_MAX ((unsigned char)~0)
 35 #endif
 36 #include "bcdefs.h"
 37 #include "proto.h"
 38 #include "global.h"
 39 #include "dc.h"
 40 #include "dc-proto.h"
 41 
 42 #ifdef __GNUC__
 43 # define ATTRIB(x) __attribute__(x)
 44 #else
 45 # define ATTRIB(x)
 46 #endif
 47 
 48 /* there is no POSIX standard for dc, so we'll take the GNU definitions */
 49 int std_only = FALSE;
 50 
 51 /* convert an opaque dc_num into a real bc_num */
 52 #define CastNum(x)  ((bc_num)(x))
 53 
 54 /* add two dc_nums, place into *result;
 55  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
 56  */
 57 int
 58 dc_add DC_DECLARG((a, b, kscale, result))
 59     dc_num a DC_DECLSEP
 60     dc_num b DC_DECLSEP
 61     int kscale ATTRIB((unused)) DC_DECLSEP
 62     dc_num *result DC_DECLEND
 63 {
 64     init_num((bc_num *)result);
 65     bc_add(CastNum(a), CastNum(b), (bc_num *)result, 0);
 66     return DC_SUCCESS;
 67 }
 68 
 69 /* subtract two dc_nums, place into *result;
 70  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
 71  */
 72 int
 73 dc_sub DC_DECLARG((a, b, kscale, result))
 74     dc_num a DC_DECLSEP
 75     dc_num b DC_DECLSEP
 76     int kscale ATTRIB((unused)) DC_DECLSEP
 77     dc_num *result DC_DECLEND
 78 {
 79     init_num((bc_num *)result);
 80     bc_sub(CastNum(a), CastNum(b), (bc_num *)result, 0);
 81     return DC_SUCCESS;
 82 }
 83 
 84 /* multiply two dc_nums, place into *result;
 85  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
 86  */
 87 int
 88 dc_mul DC_DECLARG((a, b, kscale, result))
 89     dc_num a DC_DECLSEP
 90     dc_num b DC_DECLSEP
 91     int kscale DC_DECLSEP
 92     dc_num *result DC_DECLEND
 93 {
 94     init_num((bc_num *)result);
 95     bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
 96     return DC_SUCCESS;
 97 }
 98 
 99 /* divide two dc_nums, place into *result;
100  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
101  */
102 int
103 dc_div DC_DECLARG((a, b, kscale, result))
104     dc_num a DC_DECLSEP
105     dc_num b DC_DECLSEP
106     int kscale DC_DECLSEP
107     dc_num *result DC_DECLEND
108 {
109     init_num((bc_num *)result);
110     if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
111         fprintf(stderr, "%s: divide by zero\n", progname);
112         return DC_DOMAIN_ERROR;
113     }
114     return DC_SUCCESS;
115 }
116 
117 /* divide two dc_nums, place quotient into *quotient and remainder
118  * into *remainder;
119  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
120  */
121 int
122 dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
123     dc_num a DC_DECLSEP
124     dc_num b DC_DECLSEP
125     int kscale DC_DECLSEP
126     dc_num *quotient DC_DECLSEP
127     dc_num *remainder DC_DECLEND
128 {
129     init_num((bc_num *)quotient);
130     init_num((bc_num *)remainder);
131     if (bc_divmod(CastNum(a), CastNum(b),
132                         (bc_num *)quotient, (bc_num *)remainder, kscale)){
133         fprintf(stderr, "%s: divide by zero\n", progname);
134         return DC_DOMAIN_ERROR;
135     }
136     return DC_SUCCESS;
137 }
138 
139 /* place the reminder of dividing a by b into *result;
140  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
141  */
142 int
143 dc_rem DC_DECLARG((a, b, kscale, result))
144     dc_num a DC_DECLSEP
145     dc_num b DC_DECLSEP
146     int kscale DC_DECLSEP
147     dc_num *result DC_DECLEND
148 {
149     init_num((bc_num *)result);
150     if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
151         fprintf(stderr, "%s: remainder by zero\n", progname);
152         return DC_DOMAIN_ERROR;
153     }
154     return DC_SUCCESS;
155 }
156 
157 int
158 dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
159     dc_num base DC_DECLSEP
160     dc_num expo DC_DECLSEP
161     dc_num mod DC_DECLSEP
162     int kscale DC_DECLSEP
163     dc_num *result DC_DECLEND
164 {
165     init_num((bc_num *)result);
166     if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
167                     (bc_num *)result, kscale)){
168         if (is_zero(CastNum(mod)))
169             fprintf(stderr, "%s: remainder by zero\n", progname);
170         return DC_DOMAIN_ERROR;
171     }
172     return DC_SUCCESS;
173 }
174 
175 /* place the result of exponentiationg a by b into *result;
176  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
177  */
178 int
179 dc_exp DC_DECLARG((a, b, kscale, result))
180     dc_num a DC_DECLSEP
181     dc_num b DC_DECLSEP
182     int kscale DC_DECLSEP
183     dc_num *result DC_DECLEND
184 {
185     init_num((bc_num *)result);
186     bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
187     return DC_SUCCESS;
188 }
189 
190 /* take the square root of the value, place into *result;
191  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
192  */
193 int
194 dc_sqrt DC_DECLARG((value, kscale, result))
195     dc_num value DC_DECLSEP
196     int kscale DC_DECLSEP
197     dc_num *result DC_DECLEND
198 {
199     bc_num tmp;
200 
201     tmp = copy_num(CastNum(value));
202     if (!bc_sqrt(&tmp, kscale)){
203         fprintf(stderr, "%s: square root of negative number\n", progname);
204         free_num(&tmp);
205         return DC_DOMAIN_ERROR;
206     }
207     *((bc_num *)result) = tmp;
208     return DC_SUCCESS;
209 }
210 
211 /* compare dc_nums a and b;
212  *  return a negative value if a < b;
213  *  return a positive value if a > b;
214  *  return zero value if a == b
215  */
216 int
217 dc_compare DC_DECLARG((a, b))
218     dc_num a DC_DECLSEP
219     dc_num b DC_DECLEND
220 {
221     return bc_compare(CastNum(a), CastNum(b));
222 }
223 
224 /* attempt to convert a dc_num to its corresponding int value
225  * If discard_p is DC_TOSS then deallocate the value after use.
226  */
227 int
228 dc_num2int DC_DECLARG((value, discard_p))
229     dc_num value DC_DECLSEP
230     dc_discard discard_p DC_DECLEND
231 {
232     long result;
233 
234     result = num2long(CastNum(value));
235     if (discard_p == DC_TOSS)
236         dc_free_num(&value);
237     return (int)result;
238 }
239 
240 /* convert a C integer value into a dc_num */
241 /* For convenience of the caller, package the dc_num
242  * into a dc_data result.
243  */
244 dc_data
245 dc_int2data DC_DECLARG((value))
246     int value DC_DECLEND
247 {
248     dc_data result;
249 
250     init_num((bc_num *)&result.v.number);
251     int2num((bc_num *)&result.v.number, value);
252     result.dc_type = DC_NUMBER;
253     return result;
254 }
255 
256 /* get a dc_num from some input stream;
257  *  input is a function which knows how to read the desired input stream
258  *  ibase is the input base (2<=ibase<=DC_IBASE_MAX)
259  *  *readahead will be set to the readahead character consumed while
260  *   looking for the end-of-number
261  */
262 /* For convenience of the caller, package the dc_num
263  * into a dc_data result.
264  */
265 dc_data
266 dc_getnum DC_DECLARG((input, ibase, readahead))
267     int (*input) DC_PROTO((void)) DC_DECLSEP
268     int ibase DC_DECLSEP
269     int *readahead DC_DECLEND
270 {
271     bc_num  base;
272     bc_num  result;
273     bc_num  build;
274     bc_num  tmp;
275     bc_num  divisor;
276     dc_data full_result;
277     int     negative = 0;
278     int     digit;
279     int     decimal;
280     int     c;
281 
282     init_num(&tmp);
283     init_num(&build);
284     init_num(&base);
285     result = copy_num(_zero_);
286     int2num(&base, ibase);
287     c = (*input)();
288     while (isspace(c))
289         c = (*input)();
290     if (c == '_' || c == '-'){
291         negative = c;
292         c = (*input)();
293     }else if (c == '+'){
294         c = (*input)();
295     }
296     while (isspace(c))
297         c = (*input)();
298     for (;;){
299         if (isdigit(c))
300             digit = c - '0';
301         else if ('A' <= c && c <= 'F')
302             digit = 10 + c - 'A';
303         else
304             break;
305         c = (*input)();
306         int2num(&tmp, digit);
307         bc_multiply(result, base, &result, 0);
308         bc_add(result, tmp, &result, 0);
309     }
310     if (c == '.'){
311         free_num(&build);
312         free_num(&tmp);
313         divisor = copy_num(_one_);
314         build = copy_num(_zero_);
315         decimal = 0;
316         for (;;){
317             c = (*input)();
318             if (isdigit(c))
319                 digit = c - '0';
320             else if ('A' <= c && c <= 'F')
321                 digit = 10 + c - 'A';
322             else
323                 break;
324             int2num(&tmp, digit);
325             bc_multiply(build, base, &build, 0);
326             bc_add(build, tmp, &build, 0);
327             bc_multiply(divisor, base, &divisor, 0);
328             ++decimal;
329         }
330         bc_divide(build, divisor, &build, decimal);
331         bc_add(result, build, &result, 0);
332     }
333     /* Final work. */
334     if (negative)
335         bc_sub(_zero_, result, &result, 0);
336 
337     free_num(&tmp);
338     free_num(&build);
339     free_num(&base);
340     if (readahead)
341         *readahead = c;
342     full_result.v.number = (dc_num)result;
343     full_result.dc_type = DC_NUMBER;
344     return full_result;
345 }
346 
347 
348 /* return the "length" of the number */
349 int
350 dc_numlen DC_DECLARG((value))
351     dc_num value DC_DECLEND
352 {
353     bc_num num = CastNum(value);
354 
355     /* is this right??? */
356     return num->n_len + num->n_scale;
357 }
358 
359 /* return the scale factor of the passed dc_num
360  * If discard_p is DC_TOSS then deallocate the value after use.
361  */
362 int
363 dc_tell_scale DC_DECLARG((value, discard_p))
364     dc_num value DC_DECLSEP
365     dc_discard discard_p DC_DECLEND
366 {
367     int kscale;
368 
369     kscale = CastNum(value)->n_scale;
370     if (discard_p == DC_TOSS)
371         dc_free_num(&value);
372     return kscale;
373 }
374 
375 
376 /* initialize the math subsystem */
377 void
378 dc_math_init DC_DECLVOID()
379 {
380     init_numbers();
381 }
382 
383 /* print out a dc_num in output base obase to stdout;
384  * if newline_p is DC_WITHNL, terminate output with a '\n';
385  * if discard_p is DC_TOSS then deallocate the value after use
386  */
387 void
388 dc_out_num DC_DECLARG((value, obase, newline_p, discard_p))
389     dc_num value DC_DECLSEP
390     int obase DC_DECLSEP
391     dc_newline newline_p DC_DECLSEP
392     dc_discard discard_p DC_DECLEND
393 {
394     out_num(CastNum(value), obase, out_char);
395     if (newline_p == DC_WITHNL)
396         out_char('\n');
397     if (discard_p == DC_TOSS)
398         dc_free_num(&value);
399 }
400 
401 /* dump out the absolute value of the integer part of a
402  * dc_num as a byte stream, without any line wrapping;
403  * if discard_p is DC_TOSS then deallocate the value after use
404  */
405 void
406 dc_dump_num DC_DECLARG((value, discard_p))
407     dc_num dcvalue DC_DECLSEP
408     dc_discard discard_p DC_DECLEND
409 {
410     struct digit_stack { int digit; struct digit_stack *link;};
411     struct digit_stack *top_of_stack = NULL;
412     struct digit_stack *cur;
413     struct digit_stack *next;
414     bc_num value;
415     bc_num obase;
416     bc_num digit;
417 
418     init_num(&value);
419     init_num(&obase);
420     init_num(&digit);
421 
422     /* we only handle the integer portion: */
423     bc_divide(CastNum(dcvalue), _one_, &value, 0);
424     /* we only handle the absolute value: */
425     value->n_sign = PLUS;
426     /* we're done with the dcvalue parameter: */
427     if (discard_p == DC_TOSS)
428         dc_free_num(&dcvalue);
429 
430     int2num(&obase, 1+UCHAR_MAX);
431     do {
432         (void) bc_divmod(value, obase, &value, &digit, 0);
433         cur = dc_malloc(sizeof *cur);
434         cur->digit = (int)num2long(digit);
435         cur->link = top_of_stack;
436         top_of_stack = cur;
437     } while (!is_zero(value));
438 
439     for (cur=top_of_stack; cur; cur=next) {
440         putchar(cur->digit);
441         next = cur->link;
442         free(cur);
443     }
444 
445     free_num(&digit);
446     free_num(&obase);
447     free_num(&value);
448 }
449 
450 /* deallocate an instance of a dc_num */
451 void
452 dc_free_num DC_DECLARG((value))
453     dc_num *value DC_DECLEND
454 {
455     free_num((bc_num *)value);
456 }
457 
458 /* return a duplicate of the number in the passed value */
459 /* The mismatched data types forces the caller to deal with
460  * bad dc_type'd dc_data values, and makes it more convenient
461  * for the caller to not have to do the grunge work of setting
462  * up a dc_type result.
463  */
464 dc_data
465 dc_dup_num DC_DECLARG((value))
466     dc_num value DC_DECLEND
467 {
468     dc_data result;
469 
470     ++CastNum(value)->n_refs;
471     result.v.number = value;
472     result.dc_type = DC_NUMBER;
473     return result;
474 }
475 
476 
477 
478 /*---------------------------------------------------------------------------\
479 | The rest of this file consists of stubs for bc routines called by numeric.c|
480 | so as to minimize the amount of bc code needed to build dc.                |
481 | The bulk of the code was just lifted straight out of the bc source.        |
482 \---------------------------------------------------------------------------*/
483 
484 #ifdef HAVE_STDLIB_H
485 # include <stdlib.h>
486 #endif
487 
488 #ifdef HAVE_STDARG_H
489 # include <stdarg.h>
490 #else
491 # include <varargs.h>
492 #endif
493 
494 
495 int out_col = 0;
496 
497 /* Output routines: Write a character CH to the standard output.
498    It keeps track of the number of characters output and may
499    break the output with a "\<cr>". */
500 
501 void
502 out_char (ch)
503      char ch;
504 {
505 
506   if (ch == '\n')
507     {
508       out_col = 0;
509       putchar ('\n');
510     }
511   else
512     {
513       out_col++;
514       if (out_col == 70)
515     {
516       putchar ('\\');
517       putchar ('\n');
518       out_col = 1;
519     }
520       putchar (ch);
521     }
522 }
523 
524 /* Malloc could not get enough memory. */
525 
526 void
527 out_of_memory()
528 {
529   dc_memfail();
530 }
531 
532 /* Runtime error will  print a message and stop the machine. */
533 
534 #ifdef HAVE_STDARG_H
535 #ifdef __STDC__
536 void
537 rt_error (char *mesg, ...)
538 #else
539 void
540 rt_error (mesg)
541      char *mesg;
542 #endif
543 #else
544 void
545 rt_error (mesg, va_alist)
546      char *mesg;
547 #endif
548 {
549   va_list args;
550   char error_mesg [255];
551 
552 #ifdef HAVE_STDARG_H
553   va_start (args, mesg);
554 #else
555   va_start (args);
556 #endif
557   vsprintf (error_mesg, mesg, args);
558   va_end (args);
559   
560   fprintf (stderr, "Runtime error: %s\n", error_mesg);
561 }
562 
563 
564 /* A runtime warning tells of some action taken by the processor that
565    may change the program execution but was not enough of a problem
566    to stop the execution. */
567 
568 #ifdef HAVE_STDARG_H
569 #ifdef __STDC__
570 void
571 rt_warn (char *mesg, ...)
572 #else
573 void
574 rt_warn (mesg)
575      char *mesg;
576 #endif
577 #else
578 void
579 rt_warn (mesg, va_alist)
580      char *mesg;
581 #endif
582 {
583   va_list args;
584   char error_mesg [255];
585 
586 #ifdef HAVE_STDARG_H
587   va_start (args, mesg);
588 #else
589   va_start (args);
590 #endif
591   vsprintf (error_mesg, mesg, args);
592   va_end (args);
593 
594   fprintf (stderr, "Runtime warning: %s\n", error_mesg);
595 }
5761222 [rkeene@sledge /home/rkeene/devel/old/bc-dos/dc]$

Click here to go back to the directory listing.
Click here to download this file.
last modified: 1998-03-09 18:54:48