home *** CD-ROM | disk | FTP | other *** search
/ Geek Gadgets 1 / ADE-1.bin / ade-dist / bc-1.03-src.tgz / tar.out / fsf / bc / dc-number.c < prev    next >
C/C++ Source or Header  |  1996-09-28  |  11KB  |  491 lines

  1. /* 
  2.  * interface dc to the bc numeric routines
  3.  *
  4.  * Copyright (C) 1994 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.  
  24. #include "config.h"
  25.  
  26. #include <stdio.h>
  27. #include <ctype.h>
  28. #include "bcdefs.h"
  29. #include "proto.h"
  30. #include "global.h"
  31. #include "dc.h"
  32. #include "dc-proto.h"
  33.  
  34. /* convert an opaque dc_num into a real bc_num */
  35. #define CastNum(x)    ((bc_num)(x))
  36.  
  37. /* add two dc_nums, place into *result;
  38.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  39.  */
  40. int
  41. dc_add DC_DECLARG((a, b, kscale, result))
  42.     dc_num a DC_DECLSEP
  43.     dc_num b DC_DECLSEP
  44.     int kscale DC_DECLSEP
  45.     dc_num *result DC_DECLEND
  46. {
  47.     init_num((bc_num *)result);
  48.     bc_add(CastNum(a), CastNum(b), (bc_num *)result);
  49.     return DC_SUCCESS;
  50. }
  51.  
  52. /* subtract two dc_nums, place into *result;
  53.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  54.  */
  55. int
  56. dc_sub DC_DECLARG((a, b, kscale, result))
  57.     dc_num a DC_DECLSEP
  58.     dc_num b DC_DECLSEP
  59.     int kscale DC_DECLSEP
  60.     dc_num *result DC_DECLEND
  61. {
  62.     init_num((bc_num *)result);
  63.     bc_sub(CastNum(a), CastNum(b), (bc_num *)result);
  64.     return DC_SUCCESS;
  65. }
  66.  
  67. /* multiply two dc_nums, place into *result;
  68.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  69.  */
  70. int
  71. dc_mul DC_DECLARG((a, b, kscale, result))
  72.     dc_num a DC_DECLSEP
  73.     dc_num b DC_DECLSEP
  74.     int kscale DC_DECLSEP
  75.     dc_num *result DC_DECLEND
  76. {
  77.     init_num((bc_num *)result);
  78.     bc_multiply(CastNum(a), CastNum(b), (bc_num *)result, kscale);
  79.     return DC_SUCCESS;
  80. }
  81.  
  82. /* divide two dc_nums, place into *result;
  83.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  84.  */
  85. int
  86. dc_div DC_DECLARG((a, b, kscale, result))
  87.     dc_num a DC_DECLSEP
  88.     dc_num b DC_DECLSEP
  89.     int kscale DC_DECLSEP
  90.     dc_num *result DC_DECLEND
  91. {
  92.     init_num((bc_num *)result);
  93.     if (bc_divide(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
  94.         fprintf(stderr, "%s: divide by zero\n", progname);
  95.         return DC_DOMAIN_ERROR;
  96.     }
  97.     return DC_SUCCESS;
  98. }
  99.  
  100. /* place the reminder of dividing a by b into *result;
  101.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  102.  */
  103. int
  104. dc_rem DC_DECLARG((a, b, kscale, result))
  105.     dc_num a DC_DECLSEP
  106.     dc_num b DC_DECLSEP
  107.     int kscale DC_DECLSEP
  108.     dc_num *result DC_DECLEND
  109. {
  110.     init_num((bc_num *)result);
  111.     if (bc_modulo(CastNum(a), CastNum(b), (bc_num *)result, kscale)){
  112.         fprintf(stderr, "%s: remainder by zero\n", progname);
  113.         return DC_DOMAIN_ERROR;
  114.     }
  115.     return DC_SUCCESS;
  116. }
  117.  
  118. /* place the result of exponentiationg a by b into *result;
  119.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  120.  */
  121. int
  122. dc_exp DC_DECLARG((a, b, kscale, result))
  123.     dc_num a DC_DECLSEP
  124.     dc_num b DC_DECLSEP
  125.     int kscale DC_DECLSEP
  126.     dc_num *result DC_DECLEND
  127. {
  128.     init_num((bc_num *)result);
  129.     bc_raise(CastNum(a), CastNum(b), (bc_num *)result, kscale);
  130.     return DC_SUCCESS;
  131. }
  132.  
  133. /* take the square root of the value, place into *result;
  134.  * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
  135.  */
  136. int
  137. dc_sqrt DC_DECLARG((value, kscale, result))
  138.     dc_num value DC_DECLSEP
  139.     int kscale DC_DECLSEP
  140.     dc_num *result DC_DECLEND
  141. {
  142.     bc_num tmp;
  143.  
  144.     tmp = copy_num(CastNum(value));
  145.     if (!bc_sqrt(&tmp, kscale)){
  146.         fprintf(stderr, "%s: square root of negative number\n", progname);
  147.         free_num(&tmp);
  148.         return DC_DOMAIN_ERROR;
  149.     }
  150.     *((bc_num *)result) = tmp;
  151.     return DC_SUCCESS;
  152. }
  153.  
  154. /* compare dc_nums a and b;
  155.  *  return a negative value if a < b;
  156.  *  return a positive value if a > b;
  157.  *  return zero value if a == b
  158.  */
  159. int
  160. dc_compare DC_DECLARG((a, b))
  161.     dc_num a DC_DECLSEP
  162.     dc_num b DC_DECLEND
  163. {
  164.     return bc_compare(CastNum(a), CastNum(b));
  165. }
  166.  
  167. /* attempt to convert a dc_num to its corresponding int value
  168.  * If discard_flag is true then deallocate the value after use.
  169.  */
  170. int
  171. dc_num2int DC_DECLARG((value, discard_flag))
  172.     dc_num value DC_DECLSEP
  173.     dc_boolean discard_flag DC_DECLEND
  174. {
  175.     long result;
  176.  
  177.     result = num2long(CastNum(value));
  178.     if (discard_flag)
  179.         dc_free_num(&value);
  180.     return (int)result;
  181. }
  182.  
  183. /* convert a C integer value into a dc_num */
  184. /* For convenience of the caller, package the dc_num
  185.  * into a dc_data result.
  186.  */
  187. dc_data
  188. dc_int2data DC_DECLARG((value))
  189.     int value DC_DECLEND
  190. {
  191.     dc_data result;
  192.  
  193.     init_num((bc_num *)&result.v.number);
  194.     int2num((bc_num *)&result.v.number, value);
  195.      result.dc_type = DC_NUMBER;
  196.     return result;
  197. }
  198.  
  199. /* get a dc_num from some input stream;
  200.  *  input is a function which knows how to read the desired input stream
  201.  *  ibase is the input base (2<=ibase<=DC_IBASE_MAX)
  202.  *  *readahead will be set to the readahead character consumed while
  203.  *   looking for the end-of-number
  204.  */
  205. /* For convenience of the caller, package the dc_num
  206.  * into a dc_data result.
  207.  */
  208. dc_data
  209. dc_getnum DC_DECLARG((input, ibase, readahead))
  210.     int (*input) DC_PROTO((void)) DC_DECLSEP
  211.     int ibase DC_DECLSEP
  212.     int *readahead DC_DECLEND
  213. {
  214.     bc_num    base;
  215.     bc_num    result;
  216.     bc_num    build;
  217.     bc_num    tmp;
  218.     bc_num    divisor;
  219.     dc_data    full_result;
  220.     int        negative = 0;
  221.     int        digit;
  222.     int        decimal;
  223.     int        c;
  224.  
  225.     init_num(&tmp);
  226.     init_num(&build);
  227.     init_num(&base);
  228.     result = copy_num(_zero_);
  229.     int2num(&base, ibase);
  230.     c = (*input)();
  231.     while (isspace(c))
  232.         c = (*input)();
  233.     if (c == '_' || c == '-'){
  234.         negative = c;
  235.         c = (*input)();
  236.     }else if (c == '+'){
  237.         c = (*input)();
  238.     }
  239.     while (isspace(c))
  240.         c = (*input)();
  241.     for (;;){
  242.         if (isdigit(c))
  243.             digit = c - '0';
  244.         else if ('A' <= c && c <= 'F')
  245.             digit = 10 + c - 'A';
  246.         else
  247.             break;
  248.         c = (*input)();
  249.         int2num(&tmp, digit);
  250.         bc_multiply(result, base, &result, 0);
  251.         bc_add(result, tmp, &result);
  252.     }
  253.     if (c == '.'){
  254.         free_num(&build);
  255.         free_num(&tmp);
  256.         divisor = copy_num(_one_);
  257.         build = copy_num(_zero_);
  258.         decimal = 0;
  259.         for (;;){
  260.             c = (*input)();
  261.             if (isdigit(c))
  262.                 digit = c - '0';
  263.             else if ('A' <= c && c <= 'F')
  264.                 digit = 10 + c - 'A';
  265.             else
  266.                 break;
  267.             int2num(&tmp, digit);
  268.             bc_multiply(build, base, &build, 0);
  269.             bc_add(build, tmp, &build);
  270.             bc_multiply(divisor, base, &divisor, 0);
  271.             ++decimal;
  272.         }
  273.         bc_divide(build, divisor, &build, decimal);
  274.         bc_add(result, build, &result);
  275.     }
  276.     /* Final work. */
  277.     if (negative)
  278.         bc_sub(_zero_, result, &result);
  279.  
  280.     free_num(&tmp);
  281.     free_num(&build);
  282.     free_num(&base);
  283.     if (readahead)
  284.         *readahead = c;
  285.     full_result.v.number = (dc_num)result;
  286.     full_result.dc_type = DC_NUMBER;
  287.     return full_result;
  288. }
  289.  
  290.  
  291. /* return the "length" of the number */
  292. int
  293. dc_numlen DC_DECLARG((value))
  294.     dc_num value DC_DECLEND
  295. {
  296.     bc_num num = CastNum(value);
  297.  
  298.     /* is this right??? */
  299.     return num->n_len + num->n_scale;
  300. }
  301.  
  302. /* return the scale factor of the passed dc_num
  303.  * If discard_flag is true then deallocate the value after use.
  304.  */
  305. int
  306. dc_tell_scale DC_DECLARG((value, discard_flag))
  307.     dc_num value DC_DECLSEP
  308.     dc_boolean discard_flag DC_DECLEND
  309. {
  310.     int kscale;
  311.  
  312.     kscale = CastNum(value)->n_scale;
  313.     if (discard_flag)
  314.         dc_free_num(&value);
  315.     return kscale;
  316. }
  317.  
  318.  
  319. /* initialize the math subsystem */
  320. void
  321. dc_math_init DC_DECLVOID()
  322. {
  323.     init_numbers();
  324. }
  325.  
  326. /* print out a dc_num in output base obase to stdout;
  327.  * if newline is true, terminate output with a '\n';
  328.  * if discard_flag is true then deallocate the value after use
  329.  */
  330. void
  331. dc_out_num DC_DECLARG((value, obase, newline, discard_flag))
  332.     dc_num value DC_DECLSEP
  333.     int obase DC_DECLSEP
  334.     dc_boolean newline DC_DECLSEP
  335.     dc_boolean discard_flag DC_DECLEND
  336. {
  337.     out_num(CastNum(value), obase, out_char);
  338.     if (newline)
  339.         out_char('\n');
  340.     if (discard_flag)
  341.         dc_free_num(&value);
  342. }
  343.  
  344.  
  345. /* deallocate an instance of a dc_num */
  346. void
  347. dc_free_num DC_DECLARG((value))
  348.     dc_num *value DC_DECLEND
  349. {
  350.     free_num((bc_num *)value);
  351. }
  352.  
  353. /* return a duplicate of the number in the passed value */
  354. /* The mismatched data types forces the caller to deal with
  355.  * bad dc_type'd dc_data values, and makes it more convenient
  356.  * for the caller to not have to do the grunge work of setting
  357.  * up a dc_type result.
  358.  */
  359. dc_data
  360. dc_dup_num DC_DECLARG((value))
  361.     dc_num value DC_DECLEND
  362. {
  363.     dc_data result;
  364.  
  365.     ++CastNum(value)->n_refs;
  366.     result.v.number = value;
  367.     result.dc_type = DC_NUMBER;
  368.     return result;
  369. }
  370.  
  371.  
  372.  
  373. /*---------------------------------------------------------------------------\
  374. | The rest of this file consists of stubs for bc routines called by number.c |
  375. | so as to minimize the amount of bc code needed to build dc.                |
  376. | The bulk of the code was just lifted straight out of the bc source.        |
  377. \---------------------------------------------------------------------------*/
  378.  
  379. #ifdef HAVE_STDLIB_H
  380. # include <stdlib.h>
  381. #endif
  382.  
  383. #ifdef HAVE_STDARG_H
  384. # include <stdarg.h>
  385. #else
  386. # include <varargs.h>
  387. #endif
  388.  
  389.  
  390. int out_col = 0;
  391.  
  392. /* Output routines: Write a character CH to the standard output.
  393.    It keeps track of the number of characters output and may
  394.    break the output with a "\<cr>". */
  395.  
  396. void
  397. out_char (ch)
  398.      char ch;
  399. {
  400.  
  401.   if (ch == '\n')
  402.     {
  403.       out_col = 0;
  404.       putchar ('\n');
  405.     }
  406.   else
  407.     {
  408.       out_col++;
  409.       if (out_col == 70)
  410.     {
  411.       putchar ('\\');
  412.       putchar ('\n');
  413.       out_col = 1;
  414.     }
  415.       putchar (ch);
  416.     }
  417. }
  418.  
  419. /* Malloc could not get enought memory. */
  420.  
  421. void
  422. out_of_memory()
  423. {
  424.   dc_memfail();
  425. }
  426.  
  427. /* Runtime error will  print a message and stop the machine. */
  428.  
  429. #ifdef HAVE_STDARG_H
  430. #ifdef __STDC__
  431. void
  432. rt_error (char *mesg, ...)
  433. #else
  434. void
  435. rt_error (mesg)
  436.      char *mesg;
  437. #endif
  438. #else
  439. void
  440. rt_error (mesg, va_alist)
  441.      char *mesg;
  442. #endif
  443. {
  444.   va_list args;
  445.   char error_mesg [255];
  446.  
  447. #ifdef HAVE_STDARG_H
  448.   va_start (args, mesg);
  449. #else
  450.   va_start (args);
  451. #endif
  452.   vsprintf (error_mesg, mesg, args);
  453.   va_end (args);
  454.   
  455.   fprintf (stderr, "Runtime error: %s\n", error_mesg);
  456. }
  457.  
  458.  
  459. /* A runtime warning tells of some action taken by the processor that
  460.    may change the program execution but was not enough of a problem
  461.    to stop the execution. */
  462.  
  463. #ifdef HAVE_STDARG_H
  464. #ifdef __STDC__
  465. void
  466. rt_warn (char *mesg, ...)
  467. #else
  468. void
  469. rt_warn (mesg)
  470.      char *mesg;
  471. #endif
  472. #else
  473. void
  474. rt_warn (mesg, va_alist)
  475.      char *mesg;
  476. #endif
  477. {
  478.   va_list args;
  479.   char error_mesg [255];
  480.  
  481. #ifdef HAVE_STDARG_H
  482.   va_start (args, mesg);
  483. #else
  484.   va_start (args);
  485. #endif
  486.   vsprintf (error_mesg, mesg, args);
  487.   va_end (args);
  488.  
  489.   fprintf (stderr, "Runtime warning: %s\n", error_mesg);
  490. }
  491.