"Fossies" - the Fresh Open Source Software Archive

Member "bc-1.06.95/dc/numeric.c" (18 Jun 2006, 15857 Bytes) of package /linux/misc/old/bc-1.06.95.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "numeric.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.07_vs_1.07.1.

    1 /* 
    2  * interface dc to the bc numeric routines
    3  *
    4  * Copyright (C) 1994, 1997, 1998, 2000, 2005 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 write to:
   18  *   The Free Software Foundation, Inc.
   19  *   51 Franklin Street, Fifth Floor
   20  *   Boston, MA 02110-1301  USA
   21  */
   22 
   23 /* This should be the only module that knows the internals of type dc_num */
   24 /* In this particular implementation we just slather out some glue and
   25  * make use of bc's numeric routines.
   26  */
   27 
   28 /* make all the header files see that these are really the same thing;
   29  * this is acceptable because everywhere else dc_number is just referenced
   30  * as a pointer-to-incomplete-structure type
   31  */
   32 #define dc_number bc_struct
   33 
   34 #include "config.h"
   35 
   36 #include <stdio.h>
   37 #include <ctype.h>
   38 #ifdef HAVE_LIMITS_H
   39 # include <limits.h>
   40 #endif
   41 #ifndef UCHAR_MAX
   42 # define UCHAR_MAX ((unsigned char)~0)
   43 #endif
   44 #ifdef HAVE_STDLIB_H
   45 # include <stdlib.h>
   46 #endif
   47 #ifdef HAVE_ERRNO_H
   48 # include <errno.h>
   49 #else
   50   extern int errno;
   51 #endif
   52 
   53 #include "number.h"
   54 #include "dc.h"
   55 #include "dc-proto.h"
   56 
   57 #ifdef __GNUC__
   58 # if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7) 
   59 #  define ATTRIB(x) __attribute__(x)
   60 # endif
   61 #endif
   62 #ifndef ATTRIB
   63 # define ATTRIB(x)
   64 #endif
   65 
   66 /* Forward prototype */
   67 static void out_char (int);
   68 
   69 /* there is no POSIX standard for dc, so we'll take the GNU definitions */
   70 int std_only = FALSE;
   71 
   72 /* convert an opaque dc_num into a real bc_num */
   73 /* by a freak accident, these are now no-op mappings,
   74  * but leave the notation here in case that changes later
   75  * */
   76 #define CastNum(x)      (x)
   77 #define CastNumPtr(x)   (x)
   78 
   79 /* add two dc_nums, place into *result;
   80  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
   81  */
   82 int
   83 dc_add DC_DECLARG((a, b, kscale, result))
   84     dc_num a DC_DECLSEP
   85     dc_num b DC_DECLSEP
   86     int kscale ATTRIB((unused)) DC_DECLSEP
   87     dc_num *result DC_DECLEND
   88 {
   89     bc_init_num(CastNumPtr(result));
   90     bc_add(CastNum(a), CastNum(b), CastNumPtr(result), 0);
   91     return DC_SUCCESS;
   92 }
   93 
   94 /* subtract two dc_nums, place into *result;
   95  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
   96  */
   97 int
   98 dc_sub DC_DECLARG((a, b, kscale, result))
   99     dc_num a DC_DECLSEP
  100     dc_num b DC_DECLSEP
  101     int kscale ATTRIB((unused)) DC_DECLSEP
  102     dc_num *result DC_DECLEND
  103 {
  104     bc_init_num(CastNumPtr(result));
  105     bc_sub(CastNum(a), CastNum(b), CastNumPtr(result), 0);
  106     return DC_SUCCESS;
  107 }
  108 
  109 /* multiply two dc_nums, place into *result;
  110  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  111  */
  112 int
  113 dc_mul DC_DECLARG((a, b, kscale, result))
  114     dc_num a DC_DECLSEP
  115     dc_num b DC_DECLSEP
  116     int kscale DC_DECLSEP
  117     dc_num *result DC_DECLEND
  118 {
  119     bc_init_num(CastNumPtr(result));
  120     bc_multiply(CastNum(a), CastNum(b), CastNumPtr(result), kscale);
  121     return DC_SUCCESS;
  122 }
  123 
  124 /* divide two dc_nums, place into *result;
  125  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  126  */
  127 int
  128 dc_div DC_DECLARG((a, b, kscale, result))
  129     dc_num a DC_DECLSEP
  130     dc_num b DC_DECLSEP
  131     int kscale DC_DECLSEP
  132     dc_num *result DC_DECLEND
  133 {
  134     bc_init_num(CastNumPtr(result));
  135     if (bc_divide(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
  136         fprintf(stderr, "%s: divide by zero\n", progname);
  137         return DC_DOMAIN_ERROR;
  138     }
  139     return DC_SUCCESS;
  140 }
  141 
  142 /* divide two dc_nums, place quotient into *quotient and remainder
  143  * into *remainder;
  144  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  145  */
  146 int
  147 dc_divrem DC_DECLARG((a, b, kscale, quotient, remainder))
  148     dc_num a DC_DECLSEP
  149     dc_num b DC_DECLSEP
  150     int kscale DC_DECLSEP
  151     dc_num *quotient DC_DECLSEP
  152     dc_num *remainder DC_DECLEND
  153 {
  154     bc_init_num(CastNumPtr(quotient));
  155     bc_init_num(CastNumPtr(remainder));
  156     if (bc_divmod(CastNum(a), CastNum(b),
  157                         CastNumPtr(quotient), CastNumPtr(remainder), kscale)){
  158         fprintf(stderr, "%s: divide by zero\n", progname);
  159         return DC_DOMAIN_ERROR;
  160     }
  161     return DC_SUCCESS;
  162 }
  163 
  164 /* place the reminder of dividing a by b into *result;
  165  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  166  */
  167 int
  168 dc_rem DC_DECLARG((a, b, kscale, result))
  169     dc_num a DC_DECLSEP
  170     dc_num b DC_DECLSEP
  171     int kscale DC_DECLSEP
  172     dc_num *result DC_DECLEND
  173 {
  174     bc_init_num(CastNumPtr(result));
  175     if (bc_modulo(CastNum(a), CastNum(b), CastNumPtr(result), kscale)){
  176         fprintf(stderr, "%s: remainder by zero\n", progname);
  177         return DC_DOMAIN_ERROR;
  178     }
  179     return DC_SUCCESS;
  180 }
  181 
  182 int
  183 dc_modexp DC_DECLARG((base, expo, mod, kscale, result))
  184     dc_num base DC_DECLSEP
  185     dc_num expo DC_DECLSEP
  186     dc_num mod DC_DECLSEP
  187     int kscale DC_DECLSEP
  188     dc_num *result DC_DECLEND
  189 {
  190     bc_init_num(CastNumPtr(result));
  191     if (bc_raisemod(CastNum(base), CastNum(expo), CastNum(mod),
  192                     CastNumPtr(result), kscale)){
  193         if (bc_is_zero(CastNum(mod)))
  194             fprintf(stderr, "%s: remainder by zero\n", progname);
  195         return DC_DOMAIN_ERROR;
  196     }
  197     return DC_SUCCESS;
  198 }
  199 
  200 /* place the result of exponentiationg a by b into *result;
  201  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  202  */
  203 int
  204 dc_exp DC_DECLARG((a, b, kscale, result))
  205     dc_num a DC_DECLSEP
  206     dc_num b DC_DECLSEP
  207     int kscale DC_DECLSEP
  208     dc_num *result DC_DECLEND
  209 {
  210     bc_init_num(CastNumPtr(result));
  211     bc_raise(CastNum(a), CastNum(b), CastNumPtr(result), kscale);
  212     return DC_SUCCESS;
  213 }
  214 
  215 /* take the square root of the value, place into *result;
  216  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  217  */
  218 int
  219 dc_sqrt DC_DECLARG((value, kscale, result))
  220     dc_num value DC_DECLSEP
  221     int kscale DC_DECLSEP
  222     dc_num *result DC_DECLEND
  223 {
  224     bc_num tmp;
  225 
  226     tmp = bc_copy_num(CastNum(value));
  227     if (!bc_sqrt(&tmp, kscale)){
  228         fprintf(stderr, "%s: square root of negative number\n", progname);
  229         bc_free_num(&tmp);
  230         return DC_DOMAIN_ERROR;
  231     }
  232     *(CastNumPtr(result)) = tmp;
  233     return DC_SUCCESS;
  234 }
  235 
  236 /* compare dc_nums a and b;
  237  *  return a negative value if a < b;
  238  *  return a positive value if a > b;
  239  *  return zero value if a == b
  240  */
  241 int
  242 dc_compare DC_DECLARG((a, b))
  243     dc_num a DC_DECLSEP
  244     dc_num b DC_DECLEND
  245 {
  246     return bc_compare(CastNum(a), CastNum(b));
  247 }
  248 
  249 /* attempt to convert a dc_num to its corresponding int value
  250  * If discard_p is DC_TOSS then deallocate the value after use.
  251  */
  252 int
  253 dc_num2int DC_DECLARG((value, discard_p))
  254     dc_num value DC_DECLSEP
  255     dc_discard discard_p DC_DECLEND
  256 {
  257     long result;
  258 
  259     result = bc_num2long(CastNum(value));
  260     if (result == 0 && !bc_is_zero(CastNum(value))) {
  261         fprintf(stderr, "%s: value overflows simple integer; punting...\n",
  262                 progname);
  263         result = -1; /* more appropriate for dc's purposes */
  264     }
  265     if (discard_p == DC_TOSS)
  266         dc_free_num(&value);
  267     return (int)result;
  268 }
  269 
  270 /* convert a C integer value into a dc_num */
  271 /* For convenience of the caller, package the dc_num
  272  * into a dc_data result.
  273  */
  274 dc_data
  275 dc_int2data DC_DECLARG((value))
  276     int value DC_DECLEND
  277 {
  278     dc_data result;
  279 
  280     bc_init_num(CastNumPtr(&result.v.number));
  281     bc_int2num(CastNumPtr(&result.v.number), value);
  282     result.dc_type = DC_NUMBER;
  283     return result;
  284 }
  285 
  286 /* get a dc_num from some input stream;
  287  *  input is a function which knows how to read the desired input stream
  288  *  ibase is the input base (2<=ibase<=DC_IBASE_MAX)
  289  *  *readahead will be set to the readahead character consumed while
  290  *   looking for the end-of-number
  291  */
  292 /* For convenience of the caller, package the dc_num
  293  * into a dc_data result.
  294  */
  295 dc_data
  296 dc_getnum DC_DECLARG((input, ibase, readahead))
  297     int (*input) DC_PROTO((void)) DC_DECLSEP
  298     int ibase DC_DECLSEP
  299     int *readahead DC_DECLEND
  300 {
  301     bc_num  base;
  302     bc_num  result;
  303     bc_num  build;
  304     bc_num  tmp;
  305     bc_num  divisor;
  306     dc_data full_result;
  307     int     negative = 0;
  308     int     digit;
  309     int     decimal;
  310     int     c;
  311 
  312     bc_init_num(&tmp);
  313     bc_init_num(&build);
  314     bc_init_num(&base);
  315     result = bc_copy_num(_zero_);
  316     bc_int2num(&base, ibase);
  317     c = (*input)();
  318     while (isspace(c))
  319         c = (*input)();
  320     if (c == '_' || c == '-'){
  321         negative = c;
  322         c = (*input)();
  323     }else if (c == '+'){
  324         c = (*input)();
  325     }
  326     while (isspace(c))
  327         c = (*input)();
  328     for (;;){
  329         if (isdigit(c))
  330             digit = c - '0';
  331         else if ('A' <= c && c <= 'F')
  332             digit = 10 + c - 'A';
  333         else
  334             break;
  335         c = (*input)();
  336         bc_int2num(&tmp, digit);
  337         bc_multiply(result, base, &result, 0);
  338         bc_add(result, tmp, &result, 0);
  339     }
  340     if (c == '.'){
  341         bc_free_num(&build);
  342         bc_free_num(&tmp);
  343         divisor = bc_copy_num(_one_);
  344         build = bc_copy_num(_zero_);
  345         decimal = 0;
  346         for (;;){
  347             c = (*input)();
  348             if (isdigit(c))
  349                 digit = c - '0';
  350             else if ('A' <= c && c <= 'F')
  351                 digit = 10 + c - 'A';
  352             else
  353                 break;
  354             bc_int2num(&tmp, digit);
  355             bc_multiply(build, base, &build, 0);
  356             bc_add(build, tmp, &build, 0);
  357             bc_multiply(divisor, base, &divisor, 0);
  358             ++decimal;
  359         }
  360         bc_divide(build, divisor, &build, decimal);
  361         bc_add(result, build, &result, 0);
  362     }
  363     /* Final work. */
  364     if (negative)
  365         bc_sub(_zero_, result, &result, 0);
  366 
  367     bc_free_num(&tmp);
  368     bc_free_num(&build);
  369     bc_free_num(&base);
  370     if (readahead)
  371         *readahead = c;
  372     *CastNumPtr(&full_result.v.number) = result;
  373     full_result.dc_type = DC_NUMBER;
  374     return full_result;
  375 }
  376 
  377 
  378 /* Return the "length" of the number, ignoring *all* leading zeros,
  379  * (including those to the right of the radix point!)
  380  */
  381 int
  382 dc_numlen DC_DECLARG((value))
  383     dc_num value DC_DECLEND
  384 {
  385     /* XXX warning: unholy coziness with the internals of a bc_num! */
  386     bc_num num = CastNum(value);
  387     char *p = num->n_value;
  388     int i = num->n_len + num->n_scale;
  389 
  390     while (1<i && *p=='\0')
  391         --i, ++p;
  392     return i;
  393 }
  394 
  395 /* return the scale factor of the passed dc_num
  396  * If discard_p is DC_TOSS then deallocate the value after use.
  397  */
  398 int
  399 dc_tell_scale DC_DECLARG((value, discard_p))
  400     dc_num value DC_DECLSEP
  401     dc_discard discard_p DC_DECLEND
  402 {
  403     int kscale;
  404 
  405     kscale = CastNum(value)->n_scale;
  406     if (discard_p == DC_TOSS)
  407         dc_free_num(&value);
  408     return kscale;
  409 }
  410 
  411 
  412 /* initialize the math subsystem */
  413 void
  414 dc_math_init DC_DECLVOID()
  415 {
  416     bc_init_numbers();
  417 }
  418 
  419 /* print out a dc_num in output base obase to stdout;
  420  * if newline_p is DC_WITHNL, terminate output with a '\n';
  421  * if discard_p is DC_TOSS then deallocate the value after use
  422  */
  423 void
  424 dc_out_num DC_DECLARG((value, obase, newline_p, discard_p))
  425     dc_num value DC_DECLSEP
  426     int obase DC_DECLSEP
  427     dc_newline newline_p DC_DECLSEP
  428     dc_discard discard_p DC_DECLEND
  429 {
  430     out_char('\0'); /* clear the column counter */
  431     bc_out_num(CastNum(value), obase, out_char, 0);
  432     if (newline_p == DC_WITHNL)
  433         putchar ('\n');
  434     if (discard_p == DC_TOSS)
  435         dc_free_num(&value);
  436 }
  437 
  438 /* dump out the absolute value of the integer part of a
  439  * dc_num as a byte stream, without any line wrapping;
  440  * if discard_p is DC_TOSS then deallocate the value after use
  441  */
  442 void
  443 dc_dump_num DC_DECLARG((dcvalue, discard_p))
  444     dc_num dcvalue DC_DECLSEP
  445     dc_discard discard_p DC_DECLEND
  446 {
  447     struct digit_stack { int digit; struct digit_stack *link;};
  448     struct digit_stack *top_of_stack = NULL;
  449     struct digit_stack *cur;
  450     struct digit_stack *next;
  451     bc_num value;
  452     bc_num obase;
  453     bc_num digit;
  454 
  455     bc_init_num(&value);
  456     bc_init_num(&obase);
  457     bc_init_num(&digit);
  458 
  459     /* we only handle the integer portion: */
  460     bc_divide(CastNum(dcvalue), _one_, &value, 0);
  461     /* we only handle the absolute value: */
  462     value->n_sign = PLUS;
  463     /* we're done with the dcvalue parameter: */
  464     if (discard_p == DC_TOSS)
  465         dc_free_num(&dcvalue);
  466 
  467     bc_int2num(&obase, 1+UCHAR_MAX);
  468     do {
  469         (void) bc_divmod(value, obase, &value, &digit, 0);
  470         cur = dc_malloc(sizeof *cur);
  471         cur->digit = (int)bc_num2long(digit);
  472         cur->link = top_of_stack;
  473         top_of_stack = cur;
  474     } while (!bc_is_zero(value));
  475 
  476     for (cur=top_of_stack; cur; cur=next) {
  477         putchar(cur->digit);
  478         next = cur->link;
  479         free(cur);
  480     }
  481 
  482     bc_free_num(&digit);
  483     bc_free_num(&obase);
  484     bc_free_num(&value);
  485 }
  486 
  487 /* deallocate an instance of a dc_num */
  488 void
  489 dc_free_num DC_DECLARG((value))
  490     dc_num *value DC_DECLEND
  491 {
  492     bc_free_num(CastNumPtr(value));
  493 }
  494 
  495 /* return a duplicate of the number in the passed value */
  496 /* The mismatched data types forces the caller to deal with
  497  * bad dc_type'd dc_data values, and makes it more convenient
  498  * for the caller to not have to do the grunge work of setting
  499  * up a dc_type result.
  500  */
  501 dc_data
  502 dc_dup_num DC_DECLARG((value))
  503     dc_num value DC_DECLEND
  504 {
  505     dc_data result;
  506 
  507     ++CastNum(value)->n_refs;
  508     result.v.number = value;
  509     result.dc_type = DC_NUMBER;
  510     return result;
  511 }
  512 
  513 
  514 
  515 /*---------------------------------------------------------------------------\
  516 | The rest of this file consists of stubs for bc routines called by numeric.c|
  517 | so as to minimize the amount of bc code needed to build dc.                |
  518 | The bulk of the code was just lifted straight out of the bc source.        |
  519 \---------------------------------------------------------------------------*/
  520 
  521 #ifdef HAVE_STDARG_H
  522 # include <stdarg.h>
  523 #else
  524 # include <varargs.h>
  525 #endif
  526 
  527 #ifndef HAVE_STRTOL
  528 /* Maintain some of the error checking of a real strtol() on
  529  * ancient systems that lack one, but punting on the niceties
  530  * of supporting bases other than 10 and overflow checking.
  531  */
  532 long
  533 strtol(const char *s, char **end, int base)
  534 {
  535     int sign = 1;
  536     long result = 0;
  537 
  538     for (;; ++s) {
  539         if (*s == '-')
  540             sign = -sign;
  541         else if (*s != '+' && !isspace(*s))
  542             break;
  543     }
  544     while (isdigit(*s))
  545         result = 10*result + (*s++ - '0');
  546     *end = s;
  547     return result * sign;
  548 }
  549 #endif /*!HAVE_STRTOL*/
  550 
  551 
  552 static int out_col = 0;
  553 static int line_max = -1;   /* negative means "need to check environment" */
  554 #define DEFAULT_LINE_MAX 70
  555 
  556 static void
  557 set_line_max_from_environment(void)
  558 {
  559     const char *env_line_len = getenv("DC_LINE_LENGTH");
  560     line_max = DEFAULT_LINE_MAX;
  561     errno = 0;
  562     if (env_line_len) {
  563         char *endptr;
  564         long proposed_line_len = strtol(env_line_len, &endptr, 0);
  565         line_max = (int)proposed_line_len;
  566 
  567         /* silently enforce sanity */
  568         while (isspace(*endptr))
  569             ++endptr;
  570         if (*endptr || errno || line_max != proposed_line_len
  571                     || line_max < 0 || line_max == 1)
  572             line_max = DEFAULT_LINE_MAX;
  573     }
  574 }
  575 
  576 /* Output routines: Write a character CH to the standard output.
  577    It keeps track of the number of characters output and may
  578    break the output with a "\<cr>". */
  579 
  580 static void
  581 out_char (ch)
  582     int ch;
  583 {
  584     if (ch == '\0') {
  585         out_col = 0;
  586     } else {
  587         if (line_max < 0)
  588             set_line_max_from_environment();
  589         if (++out_col >= line_max && line_max != 0) {
  590             putchar ('\\');
  591             putchar ('\n');
  592             out_col = 1;
  593         }
  594         putchar(ch);
  595     }
  596 }
  597 
  598 /* Malloc could not get enough memory. */
  599 
  600 void
  601 out_of_memory()
  602 {
  603     dc_memfail();
  604 }
  605 
  606 /* Runtime error --- will print a message and stop the machine. */
  607 
  608 #ifdef HAVE_STDARG_H
  609 #ifdef __STDC__
  610 void
  611 rt_error (char *mesg, ...)
  612 #else
  613 void
  614 rt_error (mesg)
  615     char *mesg;
  616 #endif
  617 #else
  618 void
  619 rt_error (mesg, va_alist)
  620     char *mesg;
  621 #endif
  622 {
  623     va_list args;
  624 
  625     fprintf (stderr, "Runtime error: ");
  626 #ifdef HAVE_STDARG_H
  627     va_start (args, mesg);
  628 #else
  629     va_start (args);
  630 #endif
  631     vfprintf (stderr, mesg, args);
  632     va_end (args);
  633     fprintf (stderr, "\n");
  634 }
  635 
  636 
  637 /* A runtime warning tells of some action taken by the processor that
  638    may change the program execution but was not enough of a problem
  639    to stop the execution. */
  640 
  641 #ifdef HAVE_STDARG_H
  642 #ifdef __STDC__
  643 void
  644 rt_warn (char *mesg, ...)
  645 #else
  646 void
  647 rt_warn (mesg)
  648     char *mesg;
  649 #endif
  650 #else
  651 void
  652 rt_warn (mesg, va_alist)
  653     char *mesg;
  654 #endif
  655 {
  656     va_list args;
  657 
  658     fprintf (stderr, "Runtime warning: ");
  659 #ifdef HAVE_STDARG_H
  660     va_start (args, mesg);
  661 #else
  662     va_start (args);
  663 #endif
  664     vfprintf (stderr, mesg, args);
  665     va_end (args);
  666     fprintf (stderr, "\n");
  667 }
  668 
  669 
  670 /*
  671  * Local Variables:
  672  * mode: C
  673  * tab-width: 4
  674  * End:
  675  * vi: set ts=4 :
  676  */