xref: /plan9-contrib/sys/src/cmd/gs/src/zdouble.c (revision 593dc095aefb2a85c828727bbfa9da139a49bdf4)
17dd7cddfSDavid du Colombier /* Copyright (C) 1995, 1996, 1998, 1999 Aladdin Enterprises.  All rights reserved.
27dd7cddfSDavid du Colombier 
3*593dc095SDavid du Colombier   This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier   implied.
57dd7cddfSDavid du Colombier 
6*593dc095SDavid du Colombier   This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier   modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier   of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier 
10*593dc095SDavid du Colombier   For more information about licensing, please refer to
11*593dc095SDavid du Colombier   http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier   commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier   contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier   San Rafael, CA  94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier 
17*593dc095SDavid du Colombier /* $Id: zdouble.c,v 1.5 2002/06/16 03:43:50 lpd Exp $ */
187dd7cddfSDavid du Colombier /* Double-precision floating point arithmetic operators */
197dd7cddfSDavid du Colombier #include "math_.h"
207dd7cddfSDavid du Colombier #include "memory_.h"
217dd7cddfSDavid du Colombier #include "string_.h"
227dd7cddfSDavid du Colombier #include "ctype_.h"
237dd7cddfSDavid du Colombier #include "ghost.h"
247dd7cddfSDavid du Colombier #include "gxfarith.h"
257dd7cddfSDavid du Colombier #include "oper.h"
267dd7cddfSDavid du Colombier #include "store.h"
277dd7cddfSDavid du Colombier 
287dd7cddfSDavid du Colombier /*
297dd7cddfSDavid du Colombier  * Thanks to Jean-Pierre Demailly of the Institut Fourier of the
307dd7cddfSDavid du Colombier  * Universit\'e de Grenoble I <demailly@fourier.grenet.fr> for proposing
317dd7cddfSDavid du Colombier  * this package and for arranging the funding for its creation.
327dd7cddfSDavid du Colombier  *
337dd7cddfSDavid du Colombier  * These operators work with doubles represented as 8-byte strings.  When
347dd7cddfSDavid du Colombier  * applicable, they write their result into a string supplied as an argument.
357dd7cddfSDavid du Colombier  * They also accept ints and reals as arguments.
367dd7cddfSDavid du Colombier  */
377dd7cddfSDavid du Colombier 
387dd7cddfSDavid du Colombier /* Forward references */
39*593dc095SDavid du Colombier private int double_params_result(os_ptr, int, double *);
40*593dc095SDavid du Colombier private int double_params(os_ptr, int, double *);
41*593dc095SDavid du Colombier private int double_result(i_ctx_t *, int, double);
42*593dc095SDavid du Colombier private int double_unary(i_ctx_t *, double (*)(double));
437dd7cddfSDavid du Colombier 
447dd7cddfSDavid du Colombier #define dbegin_unary()\
457dd7cddfSDavid du Colombier 	os_ptr op = osp;\
467dd7cddfSDavid du Colombier 	double num;\
477dd7cddfSDavid du Colombier 	int code = double_params_result(op, 1, &num);\
487dd7cddfSDavid du Colombier \
497dd7cddfSDavid du Colombier 	if ( code < 0 )\
507dd7cddfSDavid du Colombier 	  return code
517dd7cddfSDavid du Colombier 
527dd7cddfSDavid du Colombier #define dbegin_binary()\
537dd7cddfSDavid du Colombier 	os_ptr op = osp;\
547dd7cddfSDavid du Colombier 	double num[2];\
557dd7cddfSDavid du Colombier 	int code = double_params_result(op, 2, num);\
567dd7cddfSDavid du Colombier \
577dd7cddfSDavid du Colombier 	if ( code < 0 )\
587dd7cddfSDavid du Colombier 	  return code
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier /* ------ Arithmetic ------ */
617dd7cddfSDavid du Colombier 
627dd7cddfSDavid du Colombier /* <dnum1> <dnum2> <dresult> .dadd <dresult> */
637dd7cddfSDavid du Colombier private int
zdadd(i_ctx_t * i_ctx_p)647dd7cddfSDavid du Colombier zdadd(i_ctx_t *i_ctx_p)
657dd7cddfSDavid du Colombier {
667dd7cddfSDavid du Colombier     dbegin_binary();
677dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, num[0] + num[1]);
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier /* <dnum1> <dnum2> <dresult> .ddiv <dresult> */
717dd7cddfSDavid du Colombier private int
zddiv(i_ctx_t * i_ctx_p)727dd7cddfSDavid du Colombier zddiv(i_ctx_t *i_ctx_p)
737dd7cddfSDavid du Colombier {
747dd7cddfSDavid du Colombier     dbegin_binary();
757dd7cddfSDavid du Colombier     if (num[1] == 0.0)
767dd7cddfSDavid du Colombier 	return_error(e_undefinedresult);
777dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, num[0] / num[1]);
787dd7cddfSDavid du Colombier }
797dd7cddfSDavid du Colombier 
807dd7cddfSDavid du Colombier /* <dnum1> <dnum2> <dresult> .dmul <dresult> */
817dd7cddfSDavid du Colombier private int
zdmul(i_ctx_t * i_ctx_p)827dd7cddfSDavid du Colombier zdmul(i_ctx_t *i_ctx_p)
837dd7cddfSDavid du Colombier {
847dd7cddfSDavid du Colombier     dbegin_binary();
857dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, num[0] * num[1]);
867dd7cddfSDavid du Colombier }
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier /* <dnum1> <dnum2> <dresult> .dsub <dresult> */
897dd7cddfSDavid du Colombier private int
zdsub(i_ctx_t * i_ctx_p)907dd7cddfSDavid du Colombier zdsub(i_ctx_t *i_ctx_p)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier     dbegin_binary();
937dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, num[0] - num[1]);
947dd7cddfSDavid du Colombier }
957dd7cddfSDavid du Colombier 
967dd7cddfSDavid du Colombier /* ------ Simple functions ------ */
977dd7cddfSDavid du Colombier 
987dd7cddfSDavid du Colombier /* <dnum> <dresult> .dabs <dresult> */
997dd7cddfSDavid du Colombier private int
zdabs(i_ctx_t * i_ctx_p)1007dd7cddfSDavid du Colombier zdabs(i_ctx_t *i_ctx_p)
1017dd7cddfSDavid du Colombier {
1027dd7cddfSDavid du Colombier     return double_unary(i_ctx_p, fabs);
1037dd7cddfSDavid du Colombier }
1047dd7cddfSDavid du Colombier 
1057dd7cddfSDavid du Colombier /* <dnum> <dresult> .dceiling <dresult> */
1067dd7cddfSDavid du Colombier private int
zdceiling(i_ctx_t * i_ctx_p)1077dd7cddfSDavid du Colombier zdceiling(i_ctx_t *i_ctx_p)
1087dd7cddfSDavid du Colombier {
1097dd7cddfSDavid du Colombier     return double_unary(i_ctx_p, ceil);
1107dd7cddfSDavid du Colombier }
1117dd7cddfSDavid du Colombier 
1127dd7cddfSDavid du Colombier /* <dnum> <dresult> .dfloor <dresult> */
1137dd7cddfSDavid du Colombier private int
zdfloor(i_ctx_t * i_ctx_p)1147dd7cddfSDavid du Colombier zdfloor(i_ctx_t *i_ctx_p)
1157dd7cddfSDavid du Colombier {
1167dd7cddfSDavid du Colombier     return double_unary(i_ctx_p, floor);
1177dd7cddfSDavid du Colombier }
1187dd7cddfSDavid du Colombier 
1197dd7cddfSDavid du Colombier /* <dnum> <dresult> .dneg <dresult> */
1207dd7cddfSDavid du Colombier private int
zdneg(i_ctx_t * i_ctx_p)1217dd7cddfSDavid du Colombier zdneg(i_ctx_t *i_ctx_p)
1227dd7cddfSDavid du Colombier {
1237dd7cddfSDavid du Colombier     dbegin_unary();
1247dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, -num);
1257dd7cddfSDavid du Colombier }
1267dd7cddfSDavid du Colombier 
1277dd7cddfSDavid du Colombier /* <dnum> <dresult> .dround <dresult> */
1287dd7cddfSDavid du Colombier private int
zdround(i_ctx_t * i_ctx_p)1297dd7cddfSDavid du Colombier zdround(i_ctx_t *i_ctx_p)
1307dd7cddfSDavid du Colombier {
1317dd7cddfSDavid du Colombier     dbegin_unary();
1327dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, floor(num + 0.5));
1337dd7cddfSDavid du Colombier }
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier /* <dnum> <dresult> .dsqrt <dresult> */
1367dd7cddfSDavid du Colombier private int
zdsqrt(i_ctx_t * i_ctx_p)1377dd7cddfSDavid du Colombier zdsqrt(i_ctx_t *i_ctx_p)
1387dd7cddfSDavid du Colombier {
1397dd7cddfSDavid du Colombier     dbegin_unary();
1407dd7cddfSDavid du Colombier     if (num < 0.0)
1417dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
1427dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, sqrt(num));
1437dd7cddfSDavid du Colombier }
1447dd7cddfSDavid du Colombier 
1457dd7cddfSDavid du Colombier /* <dnum> <dresult> .dtruncate <dresult> */
1467dd7cddfSDavid du Colombier private int
zdtruncate(i_ctx_t * i_ctx_p)1477dd7cddfSDavid du Colombier zdtruncate(i_ctx_t *i_ctx_p)
1487dd7cddfSDavid du Colombier {
1497dd7cddfSDavid du Colombier     dbegin_unary();
1507dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, (num < 0 ? ceil(num) : floor(num)));
1517dd7cddfSDavid du Colombier }
1527dd7cddfSDavid du Colombier 
1537dd7cddfSDavid du Colombier /* ------ Transcendental functions ------ */
1547dd7cddfSDavid du Colombier 
1557dd7cddfSDavid du Colombier private int
darc(i_ctx_t * i_ctx_p,double (* afunc)(double))156*593dc095SDavid du Colombier darc(i_ctx_t *i_ctx_p, double (*afunc)(double))
1577dd7cddfSDavid du Colombier {
1587dd7cddfSDavid du Colombier     dbegin_unary();
1597dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, (*afunc)(num) * radians_to_degrees);
1607dd7cddfSDavid du Colombier }
1617dd7cddfSDavid du Colombier /* <dnum> <dresult> .darccos <dresult> */
1627dd7cddfSDavid du Colombier private int
zdarccos(i_ctx_t * i_ctx_p)1637dd7cddfSDavid du Colombier zdarccos(i_ctx_t *i_ctx_p)
1647dd7cddfSDavid du Colombier {
1657dd7cddfSDavid du Colombier     return darc(i_ctx_p, acos);
1667dd7cddfSDavid du Colombier }
1677dd7cddfSDavid du Colombier /* <dnum> <dresult> .darcsin <dresult> */
1687dd7cddfSDavid du Colombier private int
zdarcsin(i_ctx_t * i_ctx_p)1697dd7cddfSDavid du Colombier zdarcsin(i_ctx_t *i_ctx_p)
1707dd7cddfSDavid du Colombier {
1717dd7cddfSDavid du Colombier     return darc(i_ctx_p, asin);
1727dd7cddfSDavid du Colombier }
1737dd7cddfSDavid du Colombier 
1747dd7cddfSDavid du Colombier /* <dnum> <ddenom> <dresult> .datan <dresult> */
1757dd7cddfSDavid du Colombier private int
zdatan(i_ctx_t * i_ctx_p)1767dd7cddfSDavid du Colombier zdatan(i_ctx_t *i_ctx_p)
1777dd7cddfSDavid du Colombier {
1787dd7cddfSDavid du Colombier     double result;
1797dd7cddfSDavid du Colombier 
1807dd7cddfSDavid du Colombier     dbegin_binary();
1817dd7cddfSDavid du Colombier     if (num[0] == 0) {		/* on X-axis, special case */
1827dd7cddfSDavid du Colombier 	if (num[1] == 0)
1837dd7cddfSDavid du Colombier 	    return_error(e_undefinedresult);
1847dd7cddfSDavid du Colombier 	result = (num[1] < 0 ? 180 : 0);
1857dd7cddfSDavid du Colombier     } else {
1867dd7cddfSDavid du Colombier 	result = atan2(num[0], num[1]) * radians_to_degrees;
1877dd7cddfSDavid du Colombier 	if (result < 0)
1887dd7cddfSDavid du Colombier 	    result += 360;
1897dd7cddfSDavid du Colombier     }
1907dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, result);
1917dd7cddfSDavid du Colombier }
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier /* <dnum> <dresult> .dcos <dresult> */
1947dd7cddfSDavid du Colombier private int
zdcos(i_ctx_t * i_ctx_p)1957dd7cddfSDavid du Colombier zdcos(i_ctx_t *i_ctx_p)
1967dd7cddfSDavid du Colombier {
1977dd7cddfSDavid du Colombier     return double_unary(i_ctx_p, gs_cos_degrees);
1987dd7cddfSDavid du Colombier }
1997dd7cddfSDavid du Colombier 
2007dd7cddfSDavid du Colombier /* <dbase> <dexponent> <dresult> .dexp <dresult> */
2017dd7cddfSDavid du Colombier private int
zdexp(i_ctx_t * i_ctx_p)2027dd7cddfSDavid du Colombier zdexp(i_ctx_t *i_ctx_p)
2037dd7cddfSDavid du Colombier {
2047dd7cddfSDavid du Colombier     double ipart;
2057dd7cddfSDavid du Colombier 
2067dd7cddfSDavid du Colombier     dbegin_binary();
2077dd7cddfSDavid du Colombier     if (num[0] == 0.0 && num[1] == 0.0)
2087dd7cddfSDavid du Colombier 	return_error(e_undefinedresult);
2097dd7cddfSDavid du Colombier     if (num[0] < 0.0 && modf(num[1], &ipart) != 0.0)
2107dd7cddfSDavid du Colombier 	return_error(e_undefinedresult);
2117dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 2, pow(num[0], num[1]));
2127dd7cddfSDavid du Colombier }
2137dd7cddfSDavid du Colombier 
2147dd7cddfSDavid du Colombier private int
dlog(i_ctx_t * i_ctx_p,double (* lfunc)(double))215*593dc095SDavid du Colombier dlog(i_ctx_t *i_ctx_p, double (*lfunc)(double))
2167dd7cddfSDavid du Colombier {
2177dd7cddfSDavid du Colombier     dbegin_unary();
2187dd7cddfSDavid du Colombier     if (num <= 0.0)
2197dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
2207dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, (*lfunc)(num));
2217dd7cddfSDavid du Colombier }
2227dd7cddfSDavid du Colombier /* <dposnum> <dresult> .dln <dresult> */
2237dd7cddfSDavid du Colombier private int
zdln(i_ctx_t * i_ctx_p)2247dd7cddfSDavid du Colombier zdln(i_ctx_t *i_ctx_p)
2257dd7cddfSDavid du Colombier {
2267dd7cddfSDavid du Colombier     return dlog(i_ctx_p, log);
2277dd7cddfSDavid du Colombier }
2287dd7cddfSDavid du Colombier /* <dposnum> <dresult> .dlog <dresult> */
2297dd7cddfSDavid du Colombier private int
zdlog(i_ctx_t * i_ctx_p)2307dd7cddfSDavid du Colombier zdlog(i_ctx_t *i_ctx_p)
2317dd7cddfSDavid du Colombier {
2327dd7cddfSDavid du Colombier     return dlog(i_ctx_p, log10);
2337dd7cddfSDavid du Colombier }
2347dd7cddfSDavid du Colombier 
2357dd7cddfSDavid du Colombier /* <dnum> <dresult> .dsin <dresult> */
2367dd7cddfSDavid du Colombier private int
zdsin(i_ctx_t * i_ctx_p)2377dd7cddfSDavid du Colombier zdsin(i_ctx_t *i_ctx_p)
2387dd7cddfSDavid du Colombier {
2397dd7cddfSDavid du Colombier     return double_unary(i_ctx_p, gs_sin_degrees);
2407dd7cddfSDavid du Colombier }
2417dd7cddfSDavid du Colombier 
2427dd7cddfSDavid du Colombier /* ------ Comparison ------ */
2437dd7cddfSDavid du Colombier 
2447dd7cddfSDavid du Colombier private int
dcompare(i_ctx_t * i_ctx_p,int mask)2457dd7cddfSDavid du Colombier dcompare(i_ctx_t *i_ctx_p, int mask)
2467dd7cddfSDavid du Colombier {
2477dd7cddfSDavid du Colombier     os_ptr op = osp;
2487dd7cddfSDavid du Colombier     double num[2];
2497dd7cddfSDavid du Colombier     int code = double_params(op, 2, num);
2507dd7cddfSDavid du Colombier 
2517dd7cddfSDavid du Colombier     if (code < 0)
2527dd7cddfSDavid du Colombier 	return code;
2537dd7cddfSDavid du Colombier     make_bool(op - 1,
2547dd7cddfSDavid du Colombier 	      (mask & (num[0] < num[1] ? 1 : num[0] > num[1] ? 4 : 2))
2557dd7cddfSDavid du Colombier 	      != 0);
2567dd7cddfSDavid du Colombier     pop(1);
2577dd7cddfSDavid du Colombier     return 0;
2587dd7cddfSDavid du Colombier }
2597dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .deq <bool> */
2607dd7cddfSDavid du Colombier private int
zdeq(i_ctx_t * i_ctx_p)2617dd7cddfSDavid du Colombier zdeq(i_ctx_t *i_ctx_p)
2627dd7cddfSDavid du Colombier {
2637dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 2);
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .dge <bool> */
2667dd7cddfSDavid du Colombier private int
zdge(i_ctx_t * i_ctx_p)2677dd7cddfSDavid du Colombier zdge(i_ctx_t *i_ctx_p)
2687dd7cddfSDavid du Colombier {
2697dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 6);
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .dgt <bool> */
2727dd7cddfSDavid du Colombier private int
zdgt(i_ctx_t * i_ctx_p)2737dd7cddfSDavid du Colombier zdgt(i_ctx_t *i_ctx_p)
2747dd7cddfSDavid du Colombier {
2757dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 4);
2767dd7cddfSDavid du Colombier }
2777dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .dle <bool> */
2787dd7cddfSDavid du Colombier private int
zdle(i_ctx_t * i_ctx_p)2797dd7cddfSDavid du Colombier zdle(i_ctx_t *i_ctx_p)
2807dd7cddfSDavid du Colombier {
2817dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 3);
2827dd7cddfSDavid du Colombier }
2837dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .dlt <bool> */
2847dd7cddfSDavid du Colombier private int
zdlt(i_ctx_t * i_ctx_p)2857dd7cddfSDavid du Colombier zdlt(i_ctx_t *i_ctx_p)
2867dd7cddfSDavid du Colombier {
2877dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 1);
2887dd7cddfSDavid du Colombier }
2897dd7cddfSDavid du Colombier /* <dnum1> <dnum2> .dne <bool> */
2907dd7cddfSDavid du Colombier private int
zdne(i_ctx_t * i_ctx_p)2917dd7cddfSDavid du Colombier zdne(i_ctx_t *i_ctx_p)
2927dd7cddfSDavid du Colombier {
2937dd7cddfSDavid du Colombier     return dcompare(i_ctx_p, 5);
2947dd7cddfSDavid du Colombier }
2957dd7cddfSDavid du Colombier 
2967dd7cddfSDavid du Colombier /* ------ Conversion ------ */
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier /* Take the easy way out.... */
2997dd7cddfSDavid du Colombier #define MAX_CHARS 50
3007dd7cddfSDavid du Colombier 
3017dd7cddfSDavid du Colombier /* <dnum> <dresult> .cvd <dresult> */
3027dd7cddfSDavid du Colombier private int
zcvd(i_ctx_t * i_ctx_p)3037dd7cddfSDavid du Colombier zcvd(i_ctx_t *i_ctx_p)
3047dd7cddfSDavid du Colombier {
3057dd7cddfSDavid du Colombier     dbegin_unary();
3067dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, num);
3077dd7cddfSDavid du Colombier }
3087dd7cddfSDavid du Colombier 
3097dd7cddfSDavid du Colombier /* <string> <dresult> .cvsd <dresult> */
3107dd7cddfSDavid du Colombier private int
zcvsd(i_ctx_t * i_ctx_p)3117dd7cddfSDavid du Colombier zcvsd(i_ctx_t *i_ctx_p)
3127dd7cddfSDavid du Colombier {
3137dd7cddfSDavid du Colombier     os_ptr op = osp;
3147dd7cddfSDavid du Colombier     int code = double_params_result(op, 0, NULL);
3157dd7cddfSDavid du Colombier     double num;
3167dd7cddfSDavid du Colombier     char buf[MAX_CHARS + 2];
3177dd7cddfSDavid du Colombier     char *str = buf;
3187dd7cddfSDavid du Colombier     uint len;
3197dd7cddfSDavid du Colombier     char end;
3207dd7cddfSDavid du Colombier 
3217dd7cddfSDavid du Colombier     if (code < 0)
3227dd7cddfSDavid du Colombier 	return code;
3237dd7cddfSDavid du Colombier     check_read_type(op[-1], t_string);
3247dd7cddfSDavid du Colombier     len = r_size(op - 1);
3257dd7cddfSDavid du Colombier     if (len > MAX_CHARS)
3267dd7cddfSDavid du Colombier 	return_error(e_limitcheck);
3277dd7cddfSDavid du Colombier     memcpy(str, op[-1].value.bytes, len);
3287dd7cddfSDavid du Colombier     /*
3297dd7cddfSDavid du Colombier      * We check syntax in the following way: we remove whitespace,
3307dd7cddfSDavid du Colombier      * verify that the string contains only [0123456789+-.dDeE],
3317dd7cddfSDavid du Colombier      * then append a $ and then check that the next character after
3327dd7cddfSDavid du Colombier      * the scanned number is a $.
3337dd7cddfSDavid du Colombier      */
3347dd7cddfSDavid du Colombier     while (len > 0 && isspace(*str))
3357dd7cddfSDavid du Colombier 	++str, --len;
3367dd7cddfSDavid du Colombier     while (len > 0 && isspace(str[len - 1]))
3377dd7cddfSDavid du Colombier 	--len;
3387dd7cddfSDavid du Colombier     str[len] = 0;
3397dd7cddfSDavid du Colombier     if (strspn(str, "0123456789+-.dDeE") != len)
3407dd7cddfSDavid du Colombier 	return_error(e_syntaxerror);
3417dd7cddfSDavid du Colombier     strcat(str, "$");
3427dd7cddfSDavid du Colombier     if (sscanf(str, "%lf%c", &num, &end) != 2 || end != '$')
3437dd7cddfSDavid du Colombier 	return_error(e_syntaxerror);
3447dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, num);
3457dd7cddfSDavid du Colombier }
3467dd7cddfSDavid du Colombier 
3477dd7cddfSDavid du Colombier /* <dnum> .dcvi <int> */
3487dd7cddfSDavid du Colombier private int
zdcvi(i_ctx_t * i_ctx_p)3497dd7cddfSDavid du Colombier zdcvi(i_ctx_t *i_ctx_p)
3507dd7cddfSDavid du Colombier {
3517dd7cddfSDavid du Colombier     os_ptr op = osp;
3527dd7cddfSDavid du Colombier #define alt_min_long (-1L << (arch_sizeof_long * 8 - 1))
3537dd7cddfSDavid du Colombier #define alt_max_long (~(alt_min_long))
3547dd7cddfSDavid du Colombier     static const double min_int_real = (alt_min_long * 1.0 - 1);
3557dd7cddfSDavid du Colombier     static const double max_int_real = (alt_max_long * 1.0 + 1);
3567dd7cddfSDavid du Colombier     double num;
3577dd7cddfSDavid du Colombier     int code = double_params(op, 1, &num);
3587dd7cddfSDavid du Colombier 
3597dd7cddfSDavid du Colombier     if (code < 0)
3607dd7cddfSDavid du Colombier 	return code;
3617dd7cddfSDavid du Colombier 
3627dd7cddfSDavid du Colombier     if (num < min_int_real || num > max_int_real)
3637dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
3647dd7cddfSDavid du Colombier     make_int(op, (long)num);	/* truncates toward 0 */
3657dd7cddfSDavid du Colombier     return 0;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier /* <dnum> .dcvr <real> */
3697dd7cddfSDavid du Colombier private int
zdcvr(i_ctx_t * i_ctx_p)3707dd7cddfSDavid du Colombier zdcvr(i_ctx_t *i_ctx_p)
3717dd7cddfSDavid du Colombier {
3727dd7cddfSDavid du Colombier     os_ptr op = osp;
3737dd7cddfSDavid du Colombier #define b30 (0x40000000L * 1.0)
3747dd7cddfSDavid du Colombier #define max_mag (0xffffff * b30 * b30 * b30 * 0x4000)
3757dd7cddfSDavid du Colombier     static const float min_real = -max_mag;
3767dd7cddfSDavid du Colombier     static const float max_real = max_mag;
3777dd7cddfSDavid du Colombier #undef b30
3787dd7cddfSDavid du Colombier #undef max_mag
3797dd7cddfSDavid du Colombier     double num;
3807dd7cddfSDavid du Colombier     int code = double_params(op, 1, &num);
3817dd7cddfSDavid du Colombier 
3827dd7cddfSDavid du Colombier     if (code < 0)
3837dd7cddfSDavid du Colombier 	return code;
3847dd7cddfSDavid du Colombier     if (num < min_real || num > max_real)
3857dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
3867dd7cddfSDavid du Colombier     make_real(op, (float)num);
3877dd7cddfSDavid du Colombier     return 0;
3887dd7cddfSDavid du Colombier }
3897dd7cddfSDavid du Colombier 
3907dd7cddfSDavid du Colombier /* <dnum> <string> .dcvs <substring> */
3917dd7cddfSDavid du Colombier private int
zdcvs(i_ctx_t * i_ctx_p)3927dd7cddfSDavid du Colombier zdcvs(i_ctx_t *i_ctx_p)
3937dd7cddfSDavid du Colombier {
3947dd7cddfSDavid du Colombier     os_ptr op = osp;
3957dd7cddfSDavid du Colombier     double num;
3967dd7cddfSDavid du Colombier     int code = double_params(op - 1, 1, &num);
3977dd7cddfSDavid du Colombier     char str[MAX_CHARS + 1];
3987dd7cddfSDavid du Colombier     int len;
3997dd7cddfSDavid du Colombier 
4007dd7cddfSDavid du Colombier     if (code < 0)
4017dd7cddfSDavid du Colombier 	return code;
4027dd7cddfSDavid du Colombier     check_write_type(*op, t_string);
4037dd7cddfSDavid du Colombier     /*
4047dd7cddfSDavid du Colombier      * To get fully accurate output results for IEEE double-
4057dd7cddfSDavid du Colombier      * precision floats (53 bits of mantissa), the ANSI
4067dd7cddfSDavid du Colombier      * %g default of 6 digits is not enough; 16 are needed.
4077dd7cddfSDavid du Colombier      * Unfortunately, using %.16g produces unfortunate artifacts such as
4087dd7cddfSDavid du Colombier      * 1.2 printing as 1.200000000000005.  Therefore, we print using %g,
4097dd7cddfSDavid du Colombier      * and if the result isn't accurate enough, print again
4107dd7cddfSDavid du Colombier      * using %.16g.
4117dd7cddfSDavid du Colombier      */
4127dd7cddfSDavid du Colombier     {
4137dd7cddfSDavid du Colombier 	double scanned;
4147dd7cddfSDavid du Colombier 
4157dd7cddfSDavid du Colombier 	sprintf(str, "%g", num);
4167dd7cddfSDavid du Colombier 	sscanf(str, "%lf", &scanned);
4177dd7cddfSDavid du Colombier 	if (scanned != num)
4187dd7cddfSDavid du Colombier 	    sprintf(str, "%.16g", num);
4197dd7cddfSDavid du Colombier     }
4207dd7cddfSDavid du Colombier     len = strlen(str);
4217dd7cddfSDavid du Colombier     if (len > r_size(op))
4227dd7cddfSDavid du Colombier 	return_error(e_rangecheck);
4237dd7cddfSDavid du Colombier     memcpy(op->value.bytes, str, len);
4247dd7cddfSDavid du Colombier     op[-1] = *op;
4257dd7cddfSDavid du Colombier     r_set_size(op - 1, len);
4267dd7cddfSDavid du Colombier     pop(1);
4277dd7cddfSDavid du Colombier     return 0;
4287dd7cddfSDavid du Colombier }
4297dd7cddfSDavid du Colombier 
4307dd7cddfSDavid du Colombier /* ------ Initialization table ------ */
4317dd7cddfSDavid du Colombier 
4327dd7cddfSDavid du Colombier /* We need to split the table because of the 16-element limit. */
4337dd7cddfSDavid du Colombier const op_def zdouble1_op_defs[] = {
4347dd7cddfSDavid du Colombier 		/* Arithmetic */
4357dd7cddfSDavid du Colombier     {"3.dadd", zdadd},
4367dd7cddfSDavid du Colombier     {"3.ddiv", zddiv},
4377dd7cddfSDavid du Colombier     {"3.dmul", zdmul},
4387dd7cddfSDavid du Colombier     {"3.dsub", zdsub},
4397dd7cddfSDavid du Colombier 		/* Comparison */
4407dd7cddfSDavid du Colombier     {"2.deq", zdeq},
4417dd7cddfSDavid du Colombier     {"2.dge", zdge},
4427dd7cddfSDavid du Colombier     {"2.dgt", zdgt},
4437dd7cddfSDavid du Colombier     {"2.dle", zdle},
4447dd7cddfSDavid du Colombier     {"2.dlt", zdlt},
4457dd7cddfSDavid du Colombier     {"2.dne", zdne},
4467dd7cddfSDavid du Colombier 		/* Conversion */
4477dd7cddfSDavid du Colombier     {"2.cvd", zcvd},
4487dd7cddfSDavid du Colombier     {"2.cvsd", zcvsd},
4497dd7cddfSDavid du Colombier     {"1.dcvi", zdcvi},
4507dd7cddfSDavid du Colombier     {"1.dcvr", zdcvr},
4517dd7cddfSDavid du Colombier     {"2.dcvs", zdcvs},
4527dd7cddfSDavid du Colombier     op_def_end(0)
4537dd7cddfSDavid du Colombier };
4547dd7cddfSDavid du Colombier const op_def zdouble2_op_defs[] = {
4557dd7cddfSDavid du Colombier 		/* Simple functions */
4567dd7cddfSDavid du Colombier     {"2.dabs", zdabs},
4577dd7cddfSDavid du Colombier     {"2.dceiling", zdceiling},
4587dd7cddfSDavid du Colombier     {"2.dfloor", zdfloor},
4597dd7cddfSDavid du Colombier     {"2.dneg", zdneg},
4607dd7cddfSDavid du Colombier     {"2.dround", zdround},
4617dd7cddfSDavid du Colombier     {"2.dsqrt", zdsqrt},
4627dd7cddfSDavid du Colombier     {"2.dtruncate", zdtruncate},
4637dd7cddfSDavid du Colombier 		/* Transcendental functions */
4647dd7cddfSDavid du Colombier     {"2.darccos", zdarccos},
4657dd7cddfSDavid du Colombier     {"2.darcsin", zdarcsin},
4667dd7cddfSDavid du Colombier     {"3.datan", zdatan},
4677dd7cddfSDavid du Colombier     {"2.dcos", zdcos},
4687dd7cddfSDavid du Colombier     {"3.dexp", zdexp},
4697dd7cddfSDavid du Colombier     {"2.dln", zdln},
4707dd7cddfSDavid du Colombier     {"2.dlog", zdlog},
4717dd7cddfSDavid du Colombier     {"2.dsin", zdsin},
4727dd7cddfSDavid du Colombier     op_def_end(0)
4737dd7cddfSDavid du Colombier };
4747dd7cddfSDavid du Colombier 
4757dd7cddfSDavid du Colombier /* ------ Internal procedures ------ */
4767dd7cddfSDavid du Colombier 
4777dd7cddfSDavid du Colombier /* Get some double arguments. */
4787dd7cddfSDavid du Colombier private int
double_params(os_ptr op,int count,double * pval)4797dd7cddfSDavid du Colombier double_params(os_ptr op, int count, double *pval)
4807dd7cddfSDavid du Colombier {
4817dd7cddfSDavid du Colombier     pval += count;
4827dd7cddfSDavid du Colombier     while (--count >= 0) {
4837dd7cddfSDavid du Colombier 	switch (r_type(op)) {
4847dd7cddfSDavid du Colombier 	    case t_real:
4857dd7cddfSDavid du Colombier 		*--pval = op->value.realval;
4867dd7cddfSDavid du Colombier 		break;
4877dd7cddfSDavid du Colombier 	    case t_integer:
4887dd7cddfSDavid du Colombier 		*--pval = op->value.intval;
4897dd7cddfSDavid du Colombier 		break;
4907dd7cddfSDavid du Colombier 	    case t_string:
4917dd7cddfSDavid du Colombier 		if (!r_has_attr(op, a_read) ||
4927dd7cddfSDavid du Colombier 		    r_size(op) != sizeof(double)
4937dd7cddfSDavid du Colombier 		)
4947dd7cddfSDavid du Colombier 		           return_error(e_typecheck);
4957dd7cddfSDavid du Colombier 		--pval;
4967dd7cddfSDavid du Colombier 		memcpy(pval, op->value.bytes, sizeof(double));
4977dd7cddfSDavid du Colombier 		break;
4987dd7cddfSDavid du Colombier 	    case t__invalid:
4997dd7cddfSDavid du Colombier 		return_error(e_stackunderflow);
5007dd7cddfSDavid du Colombier 	    default:
5017dd7cddfSDavid du Colombier 		return_error(e_typecheck);
5027dd7cddfSDavid du Colombier 	}
5037dd7cddfSDavid du Colombier 	op--;
5047dd7cddfSDavid du Colombier     }
5057dd7cddfSDavid du Colombier     return 0;
5067dd7cddfSDavid du Colombier }
5077dd7cddfSDavid du Colombier 
5087dd7cddfSDavid du Colombier /* Get some double arguments, and check for a double result. */
5097dd7cddfSDavid du Colombier private int
double_params_result(os_ptr op,int count,double * pval)5107dd7cddfSDavid du Colombier double_params_result(os_ptr op, int count, double *pval)
5117dd7cddfSDavid du Colombier {
5127dd7cddfSDavid du Colombier     check_write_type(*op, t_string);
5137dd7cddfSDavid du Colombier     if (r_size(op) != sizeof(double))
5147dd7cddfSDavid du Colombier 	return_error(e_typecheck);
5157dd7cddfSDavid du Colombier     return double_params(op - 1, count, pval);
5167dd7cddfSDavid du Colombier }
5177dd7cddfSDavid du Colombier 
5187dd7cddfSDavid du Colombier /* Return a double result. */
5197dd7cddfSDavid du Colombier private int
double_result(i_ctx_t * i_ctx_p,int count,double result)5207dd7cddfSDavid du Colombier double_result(i_ctx_t *i_ctx_p, int count, double result)
5217dd7cddfSDavid du Colombier {
5227dd7cddfSDavid du Colombier     os_ptr op = osp;
5237dd7cddfSDavid du Colombier     os_ptr op1 = op - count;
5247dd7cddfSDavid du Colombier 
5257dd7cddfSDavid du Colombier     ref_assign_inline(op1, op);
5267dd7cddfSDavid du Colombier     memcpy(op1->value.bytes, &result, sizeof(double));
5277dd7cddfSDavid du Colombier     pop(count);
5287dd7cddfSDavid du Colombier     return 0;
5297dd7cddfSDavid du Colombier }
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier /* Apply a unary function to a double operand. */
5327dd7cddfSDavid du Colombier private int
double_unary(i_ctx_t * i_ctx_p,double (* func)(double))533*593dc095SDavid du Colombier double_unary(i_ctx_t *i_ctx_p, double (*func)(double))
5347dd7cddfSDavid du Colombier {
5357dd7cddfSDavid du Colombier     dbegin_unary();
5367dd7cddfSDavid du Colombier     return double_result(i_ctx_p, 1, (*func)(num));
5377dd7cddfSDavid du Colombier }
538