2 * interface dc to the bc numeric routines
4 * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
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)
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.
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:
19 * The Free Software Foundation, Inc.
20 * 59 Temple Place, Suite 330
21 * Boston, MA 02111 USA
24 /* This should be the only module that knows the internals of type dc_num */
25 /* In this particular implementation we just slather out some glue and
26 * make use of bc's numeric routines.
36 # define UCHAR_MAX ((unsigned char)~0)
44 # if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__-0 >= 7)
45 # define ATTRIB(x) __attribute__(x)
52 /* Forward prototype */
53 static void out_char (int);
55 /* there is no POSIX standard for dc, so we'll take the GNU definitions */
58 /* convert an opaque dc_num into a real bc_num */
59 #define CastNum(x) ((bc_num)(x))
61 /* add two dc_nums, place into *result;
62 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
65 dc_add
DC_DECLARG((a
, b
, kscale
, result
))
68 int kscale
ATTRIB((unused
)) DC_DECLSEP
69 dc_num
*result DC_DECLEND
71 bc_init_num((bc_num
*)result
);
72 bc_add(CastNum(a
), CastNum(b
), (bc_num
*)result
, 0);
76 /* subtract two dc_nums, place into *result;
77 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
80 dc_sub
DC_DECLARG((a
, b
, kscale
, result
))
83 int kscale
ATTRIB((unused
)) DC_DECLSEP
84 dc_num
*result DC_DECLEND
86 bc_init_num((bc_num
*)result
);
87 bc_sub(CastNum(a
), CastNum(b
), (bc_num
*)result
, 0);
91 /* multiply two dc_nums, place into *result;
92 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
95 dc_mul
DC_DECLARG((a
, b
, kscale
, result
))
99 dc_num
*result DC_DECLEND
101 bc_init_num((bc_num
*)result
);
102 bc_multiply(CastNum(a
), CastNum(b
), (bc_num
*)result
, kscale
);
106 /* divide two dc_nums, place into *result;
107 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
110 dc_div
DC_DECLARG((a
, b
, kscale
, result
))
113 int kscale DC_DECLSEP
114 dc_num
*result DC_DECLEND
116 bc_init_num((bc_num
*)result
);
117 if (bc_divide(CastNum(a
), CastNum(b
), (bc_num
*)result
, kscale
)){
118 fprintf(stderr
, "%s: divide by zero\n", progname
);
119 return DC_DOMAIN_ERROR
;
124 /* divide two dc_nums, place quotient into *quotient and remainder
126 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
129 dc_divrem
DC_DECLARG((a
, b
, kscale
, quotient
, remainder
))
132 int kscale DC_DECLSEP
133 dc_num
*quotient DC_DECLSEP
134 dc_num
*remainder DC_DECLEND
136 bc_init_num((bc_num
*)quotient
);
137 bc_init_num((bc_num
*)remainder
);
138 if (bc_divmod(CastNum(a
), CastNum(b
),
139 (bc_num
*)quotient
, (bc_num
*)remainder
, kscale
)){
140 fprintf(stderr
, "%s: divide by zero\n", progname
);
141 return DC_DOMAIN_ERROR
;
146 /* place the reminder of dividing a by b into *result;
147 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
150 dc_rem
DC_DECLARG((a
, b
, kscale
, result
))
153 int kscale DC_DECLSEP
154 dc_num
*result DC_DECLEND
156 bc_init_num((bc_num
*)result
);
157 if (bc_modulo(CastNum(a
), CastNum(b
), (bc_num
*)result
, kscale
)){
158 fprintf(stderr
, "%s: remainder by zero\n", progname
);
159 return DC_DOMAIN_ERROR
;
165 dc_modexp
DC_DECLARG((base
, expo
, mod
, kscale
, result
))
166 dc_num base DC_DECLSEP
167 dc_num expo DC_DECLSEP
168 dc_num mod DC_DECLSEP
169 int kscale DC_DECLSEP
170 dc_num
*result DC_DECLEND
172 bc_init_num((bc_num
*)result
);
173 if (bc_raisemod(CastNum(base
), CastNum(expo
), CastNum(mod
),
174 (bc_num
*)result
, kscale
)){
175 if (bc_is_zero(CastNum(mod
)))
176 fprintf(stderr
, "%s: remainder by zero\n", progname
);
177 return DC_DOMAIN_ERROR
;
182 /* place the result of exponentiationg a by b into *result;
183 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
186 dc_exp
DC_DECLARG((a
, b
, kscale
, result
))
189 int kscale DC_DECLSEP
190 dc_num
*result DC_DECLEND
192 bc_init_num((bc_num
*)result
);
193 bc_raise(CastNum(a
), CastNum(b
), (bc_num
*)result
, kscale
);
197 /* take the square root of the value, place into *result;
198 * return DC_SUCCESS on success, DC_DOMAIN_ERROR on domain error
201 dc_sqrt
DC_DECLARG((value
, kscale
, result
))
202 dc_num value DC_DECLSEP
203 int kscale DC_DECLSEP
204 dc_num
*result DC_DECLEND
208 tmp
= bc_copy_num(CastNum(value
));
209 if (!bc_sqrt(&tmp
, kscale
)){
210 fprintf(stderr
, "%s: square root of negative number\n", progname
);
212 return DC_DOMAIN_ERROR
;
214 *((bc_num
*)result
) = tmp
;
218 /* compare dc_nums a and b;
219 * return a negative value if a < b;
220 * return a positive value if a > b;
221 * return zero value if a == b
224 dc_compare
DC_DECLARG((a
, b
))
228 return bc_compare(CastNum(a
), CastNum(b
));
231 /* attempt to convert a dc_num to its corresponding int value
232 * If discard_p is DC_TOSS then deallocate the value after use.
235 dc_num2int
DC_DECLARG((value
, discard_p
))
236 dc_num value DC_DECLSEP
237 dc_discard discard_p DC_DECLEND
241 result
= bc_num2long(CastNum(value
));
242 if (discard_p
== DC_TOSS
)
247 /* convert a C integer value into a dc_num */
248 /* For convenience of the caller, package the dc_num
249 * into a dc_data result.
252 dc_int2data
DC_DECLARG((value
))
257 bc_init_num((bc_num
*)&result
.v
.number
);
258 bc_int2num((bc_num
*)&result
.v
.number
, value
);
259 result
.dc_type
= DC_NUMBER
;
263 /* get a dc_num from some input stream;
264 * input is a function which knows how to read the desired input stream
265 * ibase is the input base (2<=ibase<=DC_IBASE_MAX)
266 * *readahead will be set to the readahead character consumed while
267 * looking for the end-of-number
269 /* For convenience of the caller, package the dc_num
270 * into a dc_data result.
273 dc_getnum
DC_DECLARG((input
, ibase
, readahead
))
274 int (*input
) DC_PROTO((void)) DC_DECLSEP
276 int *readahead DC_DECLEND
292 result
= bc_copy_num(_zero_
);
293 bc_int2num(&base
, ibase
);
297 if (c
== '_' || c
== '-'){
308 else if ('A' <= c
&& c
<= 'F')
309 digit
= 10 + c
- 'A';
313 bc_int2num(&tmp
, digit
);
314 bc_multiply(result
, base
, &result
, 0);
315 bc_add(result
, tmp
, &result
, 0);
320 divisor
= bc_copy_num(_one_
);
321 build
= bc_copy_num(_zero_
);
327 else if ('A' <= c
&& c
<= 'F')
328 digit
= 10 + c
- 'A';
331 bc_int2num(&tmp
, digit
);
332 bc_multiply(build
, base
, &build
, 0);
333 bc_add(build
, tmp
, &build
, 0);
334 bc_multiply(divisor
, base
, &divisor
, 0);
337 bc_divide(build
, divisor
, &build
, decimal
);
338 bc_add(result
, build
, &result
, 0);
342 bc_sub(_zero_
, result
, &result
, 0);
349 full_result
.v
.number
= (dc_num
)result
;
350 full_result
.dc_type
= DC_NUMBER
;
355 /* return the "length" of the number */
357 dc_numlen
DC_DECLARG((value
))
358 dc_num value DC_DECLEND
360 bc_num num
= CastNum(value
);
362 /* is this right??? */
363 return num
->n_len
+ num
->n_scale
- (*num
->n_value
== '\0');
366 /* return the scale factor of the passed dc_num
367 * If discard_p is DC_TOSS then deallocate the value after use.
370 dc_tell_scale
DC_DECLARG((value
, discard_p
))
371 dc_num value DC_DECLSEP
372 dc_discard discard_p DC_DECLEND
376 kscale
= CastNum(value
)->n_scale
;
377 if (discard_p
== DC_TOSS
)
383 /* initialize the math subsystem */
385 dc_math_init
DC_DECLVOID()
390 /* print out a dc_num in output base obase to stdout;
391 * if newline_p is DC_WITHNL, terminate output with a '\n';
392 * if discard_p is DC_TOSS then deallocate the value after use
395 dc_out_num
DC_DECLARG((value
, obase
, newline_p
, discard_p
))
396 dc_num value DC_DECLSEP
398 dc_newline newline_p DC_DECLSEP
399 dc_discard discard_p DC_DECLEND
401 out_char('\0'); /* clear the column counter */
402 bc_out_num(CastNum(value
), obase
, out_char
, 0);
403 if (newline_p
== DC_WITHNL
)
405 if (discard_p
== DC_TOSS
)
409 /* dump out the absolute value of the integer part of a
410 * dc_num as a byte stream, without any line wrapping;
411 * if discard_p is DC_TOSS then deallocate the value after use
414 dc_dump_num
DC_DECLARG((dcvalue
, discard_p
))
415 dc_num dcvalue DC_DECLSEP
416 dc_discard discard_p DC_DECLEND
418 struct digit_stack
{ int digit
; struct digit_stack
*link
;};
419 struct digit_stack
*top_of_stack
= NULL
;
420 struct digit_stack
*cur
;
421 struct digit_stack
*next
;
430 /* we only handle the integer portion: */
431 bc_divide(CastNum(dcvalue
), _one_
, &value
, 0);
432 /* we only handle the absolute value: */
433 value
->n_sign
= PLUS
;
434 /* we're done with the dcvalue parameter: */
435 if (discard_p
== DC_TOSS
)
436 dc_free_num(&dcvalue
);
438 bc_int2num(&obase
, 1+UCHAR_MAX
);
440 (void) bc_divmod(value
, obase
, &value
, &digit
, 0);
441 cur
= dc_malloc(sizeof *cur
);
442 cur
->digit
= (int)bc_num2long(digit
);
443 cur
->link
= top_of_stack
;
445 } while (!bc_is_zero(value
));
447 for (cur
=top_of_stack
; cur
; cur
=next
) {
458 /* deallocate an instance of a dc_num */
460 dc_free_num
DC_DECLARG((value
))
461 dc_num
*value DC_DECLEND
463 bc_free_num((bc_num
*)value
);
466 /* return a duplicate of the number in the passed value */
467 /* The mismatched data types forces the caller to deal with
468 * bad dc_type'd dc_data values, and makes it more convenient
469 * for the caller to not have to do the grunge work of setting
470 * up a dc_type result.
473 dc_dup_num
DC_DECLARG((value
))
474 dc_num value DC_DECLEND
478 ++CastNum(value
)->n_refs
;
479 result
.v
.number
= value
;
480 result
.dc_type
= DC_NUMBER
;
486 /*---------------------------------------------------------------------------\
487 | The rest of this file consists of stubs for bc routines called by numeric.c|
488 | so as to minimize the amount of bc code needed to build dc. |
489 | The bulk of the code was just lifted straight out of the bc source. |
490 \---------------------------------------------------------------------------*/
499 # include <varargs.h>
505 /* Output routines: Write a character CH to the standard output.
506 It keeps track of the number of characters output and may
507 break the output with a "\<cr>". */
531 /* Malloc could not get enough memory. */
539 /* Runtime error will print a message and stop the machine. */
544 rt_error (char *mesg
, ...)
552 rt_error (mesg
, va_alist
)
558 fprintf (stderr
, "Runtime error: ");
560 va_start (args
, mesg
);
564 vfprintf (stderr
, mesg
, args
);
566 fprintf (stderr
, "\n");
570 /* A runtime warning tells of some action taken by the processor that
571 may change the program execution but was not enough of a problem
572 to stop the execution. */
577 rt_warn (char *mesg
, ...)
585 rt_warn (mesg
, va_alist
)
591 fprintf (stderr
, "Runtime warning: ");
593 va_start (args
, mesg
);
597 vfprintf (stderr
, mesg
, args
);
599 fprintf (stderr
, "\n");