2 static char *RCSid
= "$Id$";
6 * The Regina Rexx Interpreter
7 * Copyright (C) 1992-1994 Anders Christensen <anders@pvv.unit.no>
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Library General Public
11 * License as published by the Free Software Foundation; either
12 * version 2 of the License, or (at your option) any later version.
14 * This library is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Library General Public License for more details.
19 * You should have received a copy of the GNU Library General Public
20 * License along with this library; if not, write to the Free
21 * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
31 #define log_xor(a,b) (( (a)&&(!(b)) ) || ( (!(a)) && (b) ))
33 # define MAX(a,b) ((a>b)?(a):(b))
36 # define MIN(a,b) ((a<b)?(a):(b))
38 #define IS_AT_LEAST(ptr,now,min) \
39 if (now<min) { if (ptr) FreeTSD(ptr); ptr=MallocTSD(now=min) ; } ;
42 /* hmmm perhaps it should be rebuilt, so that 0 gave: size=0 and num
43 and exp undefined, that would be most logical ... */
46 #define MAX_EXPONENT (999999999)
48 typedef struct { /* mat_tsd: static variables of this module (thread-safe) */
64 int ClassicFormat
; /* For testing purpose it is declared here and is
65 * equivalent to NotJ18 .
67 int OldRegina
; /* For testing purpose only */
69 int add_outsize
; /* This values MAY all become one. CHECK THIS! */
77 } mat_tsd_t
; /* thread-specific but only needed by this module. see
81 /* init_math initializes the module.
82 * Currently, we set up the thread specific data and check for environment
83 * variables to change debugging behaviour.
84 * The function returns 1 on success, 0 if memory is short.
86 int init_math( tsd_t
*TSD
)
90 if (TSD
->mat_tsd
!= NULL
)
93 if ((mt
= TSD
->mat_tsd
= MallocTSD(sizeof(mat_tsd_t
))) == NULL
)
95 memset(mt
,0,sizeof(mat_tsd_t
));
97 if (getenv("OLD_REGINA") != NULL
)
99 if (getenv("CLASSIC_REGINA") != NULL
)
100 mt
->ClassicFormat
= 1;
105 void mark_descrs( const tsd_t
*TSD
)
110 if (mt
->rdescr
.num
) markmemory( mt
->rdescr
.num
, TRC_MATH
) ;
111 if (mt
->sdescr
.num
) markmemory( mt
->sdescr
.num
, TRC_MATH
) ;
112 if (mt
->fdescr
.num
) markmemory( mt
->fdescr
.num
, TRC_MATH
) ;
113 if (mt
->edescr
.num
) markmemory( mt
->edescr
.num
, TRC_MATH
) ;
115 if (mt
->outptr1
) markmemory( mt
->outptr1
, TRC_MATH
) ;
116 if (mt
->outptr2
) markmemory( mt
->outptr2
, TRC_MATH
) ;
117 if (mt
->outptr3
) markmemory( mt
->outptr3
, TRC_MATH
) ;
118 if (mt
->outptr4
) markmemory( mt
->outptr4
, TRC_MATH
) ;
119 if (mt
->outptr5
) markmemory( mt
->outptr5
, TRC_MATH
) ;
121 #endif /* TRACEMEM */
124 int descr_to_int( const num_descr
*input
)
126 /* number must be integer, and must be small enough */
129 if (input
->size
<input
->exp
)
130 exiterror( ERR_INVALID_INTEGER
, 0 ) ;
131 else if (input
->size
>input
->exp
)
133 i
= MAX( 0, input
->exp
) ;
134 for (; i
<input
->size
; i
++)
136 if (input
->num
[i
]!='0')
137 exiterror( ERR_INVALID_INTEGER
, 0 ) ;
142 for (i
=0; i
<input
->size
; i
++)
144 result
= result
*10 + (input
->num
[i
] - '0') ;
152 void str_strip( num_descr
*num
)
158 if (num
->num
[0] == '0')
166 for (i
=0; i
<num
->size
-1 && num
->num
[i
]=='0'; i
++ ) ;
169 for (j
=0; j
<(num
->size
-i
); j
++)
171 num
->num
[j
] = num
->num
[j
+i
] ;
176 assert( num
->size
> 0 ) ;
179 if ((num
->size
==1) && (num
->num
[0]=='0'))
188 int getdescr( const tsd_t
*TSD
, const streng
*num
, num_descr
*descr
)
189 /* converts num into a descr and returns 0 if successfully.
190 * returns 1 in case of an error. descr contains nonsense in this case.
191 * The newly generated descr is as short as possible: leading and
192 * trailing zeros (after a period) will be cut, rounding occurs.
193 * We don't use registers and hope the compiler does it better than outselves
194 * in the optimization stage, else try in this order: c, inlen, in, out, exp.
197 const char *in
; /* num->value */
198 int inlen
; /* chars left in "in" */
199 char *out
; /* descr->num */
200 int outpos
; /* position where to write */
201 int outmax
; /* descr->max */
202 char c
, /* tmp var */
203 lastdigit
= 0; /* last digit seen for mantissa, init: error */
204 int pointseen
, /* point in mantissa seen? */
205 exp
, /* exp from mantissa */
206 exp2
, /* exp from "1E1" */
207 expminus
; /* exp in "1E-1" is negative? */
209 IS_AT_LEAST( descr
->num
, descr
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
212 inlen
= Str_len(num
);
213 /* skip leading spaces */
214 while (inlen
&& isspace(*in
))
226 if ((c
== '-') || (c
== '+'))
228 descr
->negative
= (c
== '-') ;
231 while (inlen
&& isspace(*in
)) /* skip leading spaces */
241 descr
->negative
= 0 ;
243 /* cut ending blanks first, a non blank exists (in[0]) at this point */
244 while (isspace(in
[inlen
-1]))
247 while (inlen
&& (*in
== '0')) /* skip leading zeros */
254 { /* Fast breakout in case of a plain "0" or an error */
256 descr
->num
[0] = lastdigit
;
259 if (lastdigit
== '0')
267 /* Transfer digits and check for points */
268 pointseen
= 0; /* never seen */
271 outmax
= TSD
->currlevel
->currnumsize
+1;
275 if ((c
= *in
) == '.')
289 if ((c
=='0') && (outpos
==0)) /* skip zeros in "0.0001" */
290 exp
--; /* We must be after a point, see zero parsing above */
307 /* the mantissa is correct now, check for ugly "0.0000" later */
310 /* c is *in at this point, see above */
312 if ((c
!= 'e') && (c
!= 'E'))
314 if (--inlen
== 0) /* at least one digit must follow */
319 if ((c
== '+') || (c
== '-'))
323 if (--inlen
== 0) /* at least one digit must follow */
333 exp2
= exp2
*10 + (c
- '0'); /* Hmm, no overflow checking? */
340 if (outpos
== 0) /* no digit or 0.000 with or without exp */
349 descr
->size
= outpos
;
350 assert(descr
->size
<= TSD
->currlevel
->currnumsize
+1);
354 int getdescr( const tsd_t
*TSD
, const streng
*num
, num_descr
*descr
)
356 register unsigned char *i
=NULL
, *k
=NULL
, *top
=NULL
, *start
=NULL
;
357 unsigned char *ktop
=NULL
, ch
=' ' ;
358 register int kextra
=0, skipped
=0 ;
359 register int skipzeros
=0, decipoint
=0, found_digits
=0 ;
361 IS_AT_LEAST( descr
->num
, descr
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
363 /* skip leading whitespace */
364 i
= (unsigned char *)num
->value
;
365 top
= i
+ Str_len( num
) ;
366 for ( ; (i
<top
&& isspace(ch
=*i
)); i
++ ) ; /* FGC: ordered */
368 /* set the sign, and skip more whitespace */
369 descr
->negative
= 0 ;
370 if (((ch
== '-') || (ch
== '+')) && i
<top
)
372 descr
->negative
= (*(i
++) == '-') ;
373 for ( ; (i
<top
) && (isspace(*i
)); i
++ ) ;
376 /* This is slightly confusing ... but the conventions are:
378 * decipoint - number of leading digits in descr->num that are in
379 * front of the decimal point, if any.
380 * skipzeros - number of leading zeros in the output, _after_ the
381 * decimal point, which has been skipped.
383 * 00.0004 -> decipoint=0 skipzeros=3
384 * 123.456 -> decipoint=3 skipzeros=0
385 * 0004000 -> decipoint=-1 skipzeros=-1
388 /* read all digits in number */
395 k
= (unsigned char*)descr
->num
;
396 ktop
= k
+ TSD
->currlevel
->currnumsize
+ 1 ;
399 if ( isdigit( ch
=*i
) )
406 if (decipoint
>=0) skipped
++ ;
411 assert( decipoint
<= 0 ) ;
412 skipzeros
= skipped
;
426 decipoint
= (int)( (char*)k
- (char*)descr
->num
) ;
433 if ((i
<top
) && ((ch
=='e') || (ch
=='E')))
438 if ((*(++i
) == '-') || (*i
== '+'))
439 sign
= (*(i
++) == '-') ;
441 for (tmp
=i
; (i
<top
) && (isdigit(*i
)); i
++ )
442 descr
->exp
= descr
->exp
* 10 + (*i
- '0') ;
444 if (tmp
==i
) return 1 ;
447 descr
->exp
= - descr
->exp
;
450 /* If we didn't find any non-zero digits */
451 descr
->size
= (int)( (char*)k
- (char*)descr
->num
) ;
457 descr
->exp
+= 1 - skipped
;
461 else if (decipoint
<0)
462 descr
->exp
+= descr
->size
+ kextra
;
464 descr
->exp
+= decipoint
- skipzeros
;
466 /* check for non-white-space at the end */
471 assert( descr
->size
<= TSD
->currlevel
->currnumsize
+1 ) ;
476 void str_round( num_descr
*descr
, int size
)
480 /* we can't round to zero digits */
483 if (descr
->num
[0]>='5')
485 descr
->num
[0] = '1' ;
491 descr
->num
[0] = '0' ;
493 descr
->negative
= descr
->exp
= 0 ;
499 descr
->num
[0] = '0' ;
501 descr
->exp
= descr
->negative
= 0 ;
505 /* increment size by the number of leading zeros existing */
506 for (i
=0; i
<descr
->size
&& descr
->num
[i
]=='0'; i
++) ;
509 /* do we have to round? */
510 if (descr
->size
<=size
)
513 /* set the size to the wanted value */
516 /* is it possible just to truncate? */
517 if (descr
->num
[size
] < '5')
520 /* increment next digit, and loop if that is a '9' */
523 /* can we get away with inc'ing this digit? */
524 if (descr
->num
[i
] != '9')
530 /* no, set it to zero, and inc' next digit */
531 descr
->num
[i
--] = '0' ;
533 /* if there are no more digits, move number one magnitude up */
537 /* Just check a few things ... I don't like surprises */
538 for (i
=0; i
<size
; i
++)
539 assert( descr
->num
[i
] == '0' ) ;
542 /* increase order of magnitude, and set first digit */
544 descr
->num
[0] = '1' ;
552 void descr_copy( const tsd_t
*TSD
, const num_descr
*f
, num_descr
*s
)
555 * Check for the special case that these are identical, then we don't
556 * have to do any copying, so just return.
561 s
->negative
= f
->negative
;
565 IS_AT_LEAST( s
->num
, s
->max
, f
->size
) ;
566 memcpy( s
->num
, f
->num
, f
->size
) ;
574 * So, why don't we just flush the changes into the result string
575 * directly, without temporarily storing it in the out string? Well,
576 * the answer is that if this function is called like:
578 * string_add( TSD, &descr1, &descr2, &descr1 )
580 * then it should be able to produce the correct answer, which is
581 * impossible to do without a temporary storage. (Hmmm. No, that is
582 * bogos, it just takes a bit of care to not overwrite anything that
583 * we might need. Must be rewritten). Another problem, if the result
584 * string is to small to hold the answer, we must reallocate space
585 * so we might have to live with the out anyway.
587 void string_add( const tsd_t
*TSD
, const num_descr
*f
, const num_descr
*s
, num_descr
*r
)
589 int count1
=0, carry
=0, tmp
=0, sum
=0, neg
=0 ;
590 int lsd
=0 ; /* least significant digit */
591 int msd
=0, loan
=0, ccns
=0 ;
592 int flog
=0, fexp
=0, fsize
=0, slog
=0, ssize
=0, sexp
=0, sdiff
=0, fdiff
=0 ;
593 char *fnum
=NULL
, *snum
=NULL
;
602 flog
= f
->negative
& !s
->negative
;
603 slog
= s
->negative
& !f
->negative
;
604 sdiff
= sexp
- ssize
;
605 fdiff
= fexp
- fsize
;
610 * Make sure that we have enough space for the internal use.
612 ccns
= TSD
->currlevel
->currnumsize
;
613 IS_AT_LEAST( mt
->add_out
, mt
->add_outsize
, ccns
+2 ) ;
615 mt
->outptr5
= mt
->add_out
;
619 * If *s is zero compared to *f under NUMERIC DIGITS, set it to zero
620 * This also applies if *s is zero. TRL says that in that case, the
621 * other number is to be returned.
623 if ((ssize
==1)&&(snum
[0]=='0'))
625 descr_copy( TSD
, f
, r
) ;
630 * And do the same thing for *f
632 if (( fsize
==1)&&(fnum
[0]=='0'))
634 descr_copy( TSD
, s
, r
) ;
640 if (sexp
> fexp
+ ccns
)
642 descr_copy( TSD
, s
, r
) ;
648 if (fexp
> sexp
+ ccns
)
650 descr_copy( TSD
, f
, r
) ;
656 * Find the exponent number for the most significant digit and the
657 * least significant digit. 'size' is the size of the result, minus
658 * any extra carry. 'count1' is the loop variable that iterates
659 * through each digit.
661 * These initializations may look a bit complex, so there is a
662 * description of what they really means, consider the following
668 * The 'lsd' is the fourth digit after the decimal point, and is
669 * therefore set to -3. The 'msd' is the fifth digit before the
670 * decimal point, and is therefore set to 5. The size is set to
671 * the difference between them, that is 8.
672 * The 'carry' and 'loan' are initially
675 * Special consideration is taken, so that 'lsd' will never be more
676 * so small that the difference between them are bigger than the
679 msd
= MAX( fexp
, sexp
) ;
680 lsd
= MAX( msd
-(TSD
->currlevel
->currnumsize
+1), MIN( fdiff
, sdiff
));
684 * Loop through the numbers, from the 'lsd' to the 'msd', letting
685 * 'count1' have the value of the current digit.
689 /* The faster (and correct) algorithm uses fnum- and snum-pointers which
690 are initially set to perhaps illegal values. They become valid by
691 an offset. This isn't correctly understood by the bounds checker.
692 We use valid base pointers and a complex index here. See below for
693 the faster code. WARNING: Changes should be done both here and in the
694 '#else' - statement. FGC
696 for (count1
=lsd
; count1
<msd
; count1
++ )
699 * The variable 'sum' collects the sum for the addition of the
700 * current digit. This is done, in five steps. First, register
701 * any old value stored in 'carry' or 'loan'.
706 * Then, for each of the two numbers, add its digit to 'sum'.
707 * There are two considerations to be taken. First, are we
708 * within the range of that number. Then what are the sign of
709 * the number. The expression of the if statement checks for
710 * the validity of the range, and the contents of the if
711 * statement adds the digit to 'sum' taking note of the sign.
713 if (count1
>=fdiff
&& fexp
>count1
)
715 tmp
= fnum
[fexp
- 1 - count1
] - '0';
725 * Repeat previous step for the second number
727 if (count1
>=sdiff
&& sexp
>count1
)
729 tmp
= snum
[sexp
- 1 - count1
] - '0';
739 * If the sum is more than 9, we have a carry, then set 'carry'
740 * and subtract 10. And similar, if the sum is less than 0,
741 * set 'loan' and add 10.
743 if ((carry
= ( sum
> 9 )))
746 if ((loan
= ( sum
< 0 )))
750 * Flush the resulting digit to the output string.
752 mt
->add_out
[ msd
- count1
] = (char) (sum
+ '0');
757 for (count1
=lsd
; count1
<msd
; count1
++ )
760 * The variable 'sum' collects the sum for the addition of the
761 * current digit. This is done, in five steps. First, register
762 * any old value stored in 'carry' or 'loan'.
767 * Then, for each of the two numbers, add its digit to 'sum'.
768 * There are two considerations to be taken. First, are we
769 * within the range of that number. Then what are the sign of
770 * the number. The expression of the if statement checks for
771 * the validity of the range, and the contents of the if
772 * statement adds the digit to 'sum' taking note of the sign.
774 if (count1
>=fdiff
&& fexp
>count1
)
776 tmp
= fnum
[-count1
] - '0';
786 * Repeat previous step for the second number
788 if (count1
>=sdiff
&& sexp
>count1
)
790 tmp
= snum
[-count1
] - '0';
800 * If the sum is more than 9, we have a carry, then set 'carry'
801 * and subtract 10. And similar, if the sum is less than 0,
802 * set 'loan' and add 10.
804 if ((carry
= ( sum
> 9 )) != 0)
807 if ((loan
= ( sum
< 0 )) != 0)
811 * Flush the resulting digit to the output string.
813 mt
->add_out
[ msd
- count1
] = (char) (sum
+ '0');
817 neg
= ( f
->negative
&& s
->negative
) ;
818 IS_AT_LEAST( r
->num
, r
->max
, /*ccns+2*/ msd
-lsd
+3 ) ;
830 mt
->add_out
[0] = '0' ;
832 for ( i
=msd
-lsd
; i
>0; i
-- )
834 if ((mt
->add_out
[i
] = (char) (sum
- (mt
->add_out
[i
]-'0') + '0')) > '9')
836 mt
->add_out
[i
] = '0' ;
852 r
->size
= r
->exp
- lsd
;
855 memcpy( fnum
, mt
->add_out
+1, r
->size
- ( (carry
) ? 1 : 0 ) ) ;
857 memcpy( fnum
, mt
->add_out
+1, r
->size
) ;
860 /* for (; count1<fsize; count1++)
861 fnum[count1] = mt->add_out[count1] ;
866 streng
*str_format_orig( const tsd_t
*TSD
, const streng
*input
, int before
, int after
, int expp
, int expt
)
868 static char *out
=NULL
;
869 static int outsize
=0 ;
870 int sdigs
=0, trigger
=0, j
=0, size
=0, k
=0 ;
871 int decim
, use_exp
=0, use_eng
=0 ;
873 streng
*result
=NULL
;
875 char *in_ptr
; /* ptr to current char in input string */
876 char *in_end
; /* ptr to end+1 in input string */
877 int exponent
; /* the value of the exponent */
878 char *out_ptr
; /* ptr to current char in output string */
883 if (getdescr(TSD
,input
,&mt
->fdescr
))
884 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
886 str_round( &mt
->fdescr
, TSD
->currlevel
->currnumsize
) ;
889 * Make sure that we have enough space available. If we have memory
890 * tracing enabled, remember to save the info about the new memory
893 IS_AT_LEAST( out
, outsize
, 3*TSD
->currlevel
->currnumsize
+5 ) ;
900 * Str_ip leading zeros from the descriptor. We could have done this
901 * by calling strip(), but it is faster to do it here. Besides doing
902 * it this way shortcuts the need to shift (i.e copy) the digits
904 str_strip( &mt
->fdescr
) ;
905 exponent
= mt
->fdescr
.exp
;
906 in_end
= &mt
->fdescr
.num
[mt
->fdescr
.size
] ;
907 in_ptr
= mt
->fdescr
.num
;
910 * Now, let us see if we've got a zero. That one is a special case,
911 * and then just return a zero, no more, no less
915 return Str_creTSD( "0" ) ;
918 * There are certain limits that the .exp must be within, the 32
919 * bit integer can hold slightly larger numbers, so if we are outside
920 * the legal range, report an error.
922 if ((MAX_EXPONENT
<exponent
-1) || ((-MAX_EXPONENT
)>exponent
+1))
923 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
926 * Set 'sdigs' to the number of significant digits we want in the
927 * answer. Whatever the user wants, we first round off 'in' to
928 * the precision before doing anyting.
930 sdigs
= MIN( in_end
-in_ptr
, TSD
->currlevel
->currnumsize
) ; /* significant digits in answer */
932 /* Are we in for exponential form? If the integer part is bigger
933 * than a trigger value, or the decimal part bigger than twice that
934 * trigger value, use exponential form. The default for trigger is
935 * the precision, but it will be expt if that is defined.
937 * Problem: will the setting of before and after effect the
938 * precision on such a way that it will change the representation
939 * between exponential/simple form. (I don't think so?) The code
940 * that considers 'after' has therefore been commented out. Consider
941 * the problem format('0.00011111',,4,,3). Now, this number needs
942 * eight digits after the decimal point in order to be represented.
943 * On the other hand, it only need four digits, in the output.
944 * Which is the correct??? I don't know, but I think the code should
947 trigger
= (expt
!=(-1)) ? expt
: TSD
->currlevel
->currnumsize
;
948 decim
= MAX( sdigs
- exponent
, 0 ) ;
950 use_exp
= ((decim
>2*trigger
) || (trigger
<exponent
)) ;
954 /* If expp is zero, then we will never use exponential form
959 /* Here comes the big question, are we going to use exponential form
960 * or simple form, 'use_exp' holds the answer
964 /* We are going to use exponential form, now we have to check
965 * whether to use scientific or engineering form. In exponential
966 * form, there are *always* an integer part, which size is 1 in
967 * sci. form and 1-3 in eng. form. Now, there are a total of three
968 * ways to do this: sci, eng and custom (i.e. before is set too).
970 use_eng
= (TSD
->currlevel
->numform
== NUM_FORM_ENG
) ;
972 /* If number is 99.995, we might have to reconsider the integer
973 * part (even the length of the integer part) after rounding the
974 * fractional part. So we better round it right away, and do
975 * something sensible if order of magnitude changed.
981 str_round( &mt
->fdescr
, after
+ 1 + exponent
%2 ) ;
983 str_round( &mt
->fdescr
, after
+ 1 ) ;
985 if (k
!=mt
->fdescr
.exp
)
989 /* If 'before' was specified, we need to initialize the first
990 * chars in out to spaces, and set 'k' so we skip over them.
994 out_ptr
= out
+ before
- (mt
->fdescr
.negative
!=0) - 1 ;
996 out_ptr
-= (exponent
)%3 ;
998 /* Now, check that there is enough space, and set the initial
999 * characters that we are not going to use to spaces.
1002 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1004 /* Then set the initial characters to space. When this is done,
1005 * we are sure (almost, at least) that there we have set k to
1006 * point to the 'right' char, so that after the sign and the
1007 * integer part of the matissa has been written out, k will be
1008 * at the k'th position of the output string.
1010 for (tmp_ptr
=out
; tmp_ptr
<out_ptr
; *(tmp_ptr
++)=' ') ;
1016 * Let's start with the sign, that is not effected by any of the
1017 * various formats at which this routine can output 'in'
1019 if (mt
->fdescr
.negative
)
1020 *(out_ptr
++) = '-' ;
1022 /* Then continue with the first digit, that shall *always* be
1023 * written out, both in sci and eng form.
1025 assert( in_ptr
< in_end
) ;
1026 *(out_ptr
++) = *(in_ptr
++) ;
1029 /* If we use eng. form, we might have to stuff into it as much
1030 * as two additional digits. And we have to watch out so we neigher
1031 * increase the precision nor use more digits than we are allowed
1038 /* Break out of this when the exponent is a multiple of three.
1040 if ((exponent
%3)==0)
1043 /* First, check to see if there are more digits in the number
1044 * that we want to write out. If that is ok, then just write
1045 * the whole thing out.
1047 if (in_ptr
>= in_end
)
1048 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1049 *(out_ptr
++) = *(in_ptr
++) ;
1055 /* OK, now we have written out the integer part of the matissa. Now
1056 * we must follow with the decimal part. First of all, let us start
1057 * with the decimal point, which should only be present if the
1058 * actually are a decimal part.
1061 after
= in_end
- in_ptr
;
1064 *(out_ptr
++) = '.' ;
1066 /* At last we have to to fill in the digits in the decimal part of
1067 * the matissa. Just loop through it.
1069 for (; (after
) && (in_ptr
< in_end
); after
--)
1070 *(out_ptr
++) = *(in_ptr
++) ;
1072 /* And then we have to add the required number of tailing zeros in
1075 for (; after
; after
--)
1076 *(out_ptr
++) = '0' ;
1078 /* Then comes the exponent. It should not be written if the
1079 * exponent is one. On the other hand, if a particular size is
1080 * requested for the exponent in expp, then the appropriate number
1081 * of space should be filled in.
1085 *(out_ptr
++) = 'E' ;
1086 *(out_ptr
++) = (char) ((exponent
>0) ? '+' : '-') ;
1089 exponent
= -exponent
;
1091 /* Now, suppose that expp is unspecified, then we would have to
1092 * find the number of characters needed for the exponent. The
1093 * following is a kludge to set expp to the 'right' number if
1094 * it was previously unset.
1098 for (k
=exponent
,expp
=0; k
; k
/=10, expp
++)
1102 /* We have to fill in numbers from the end of it, and pad with
1103 * zeros to the left. First find the end, and then loop backwards
1104 * for each significant digit in exponent
1106 for (tmp_ptr
=out_ptr
+expp
-1;;)
1108 /* First check for overflow, i.e the space reserved in the
1109 * exponent is not enough to hold it.
1111 if (tmp_ptr
<out_ptr
)
1112 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1114 /* Then extract the decimal digit and put it into the output
1115 * string, while deviding the exponent by ten.
1117 *(tmp_ptr
--) = (char) (exponent
%10 + '0') ;
1120 /* The only possible way out of this is when the exponent is
1121 * zero, i.e. it has been written out. (unless an error is
1122 * trapped in the lines above.)
1128 /* Now there might be some chars left in the exponent that has
1129 * to be set to leading zeros, check it and do it.
1131 for (; tmp_ptr
>=out_ptr
;)
1132 *(tmp_ptr
--) = '0' ;
1134 /* At last, set k, so that we know the real size of the out
1139 else if (expp
!=(-1))
1141 for (j
=(-2); j
<expp
; j
++)
1142 *(out_ptr
++) = ' ' ;
1147 /* If number is 99.995, we might have to reconsider the integer
1148 * part (even the length of the integer part) after rounding the
1149 * fractional part. So we better round it right away, and do
1150 * something sensible if order of magnitude changed.
1153 k
= mt
->fdescr
.exp
;
1156 str_round( &mt
->fdescr
, after
+ mt
->fdescr
.exp
) ;
1157 if (k
!=mt
->fdescr
.exp
)
1162 /* We are not going to use an exponent. Our number will consist of
1163 * two parts, the integer part, and the fractional part. Let us
1164 * concentrate on the integer part, which will have a particular
1165 * length if before is set.
1169 /* Since the integer part is going to have a particular length,
1170 * we better find that lenght, and skip the initial part (or
1171 * give an error if the length given is too small for this
1172 * number. Remember that we need at least on digit before the
1173 * decimal point (the leading zero).
1175 size
= (mt
->fdescr
.negative
) + MAX(exponent
, 1) ;
1177 /* Does the integer part of the output string hold enough chars?
1178 * If not, report an error. If is does, initialize the first
1179 * part of it (the unused part) to spaces.
1182 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1185 for (k
=0; k
<(before
-size
); k
++)
1186 *(out_ptr
++) = ' ' ;
1190 /* Write out the sign if it is needed, and then loop trough the
1191 * digits of the integer part of the number. If the integer part
1192 * in empty, write out a "0" instead.
1194 if (mt
->fdescr
.negative
)
1195 *(out_ptr
++) = '-' ;
1198 for (; (exponent
) && (in_ptr
<in_end
); exponent
--)
1199 *(out_ptr
++) = *(in_ptr
++) ;
1201 *(out_ptr
++) = '0' ;
1204 * If the number doesn't have enough digits to fill the integer
1205 * part, help it, and fill it with zeros.
1209 for (; exponent
; exponent
--)
1210 *(out_ptr
++) = '0' ;
1213 /* Now has the time come for the decimal points, which is only
1214 * to be written out if there actually are decimals, and if
1215 * the size of the decimal part is non-zero. First find the
1216 * number of decimals, and stuff it into the 'size' variable
1221 after
= in_end
- in_ptr
;
1223 /* If there are decimals, write the decimal point
1226 *(out_ptr
++) = '.' ;
1228 /* Then write the leading zeros after the decimal point, but
1229 * before the first digit in the number, if there are any
1231 for (j
=0; (j
<after
) && (exponent
<0); exponent
++, j
++)
1232 *(out_ptr
++) = '0' ;
1234 /* And then loop through the decimals, and write them out.
1235 * Remember that size might be larger than the actual number
1236 * of decimals available.
1238 for (; (in_ptr
<in_end
) && (j
<after
); j
++)
1239 *(out_ptr
++) = *(in_ptr
++) ;
1241 /* Then append the right number of zeros, to pad the number
1242 * to the wanted length. Here k is the length of the number
1244 for (; j
<after
; j
++)
1245 *(out_ptr
++) = '0' ;
1248 result
= Str_makeTSD( out_ptr
- out
) ;
1249 memcpy( result
->value
, out
, result
->len
=out_ptr
-out
) ;
1253 streng
*str_format(tsd_t
*TSD
, const streng
*input
, int Before
,
1254 int After
, int Expp
, int Expt
)
1255 /* According to ANSI X3J18-199X, 9.4.2, this function performs the BIF "format"
1256 * with extensions made by Brian.
1257 * I rewrote the complete function to allow comparing of this function code
1258 * to that one made in Rexx originally.
1259 * input is the first arg to "format" and may not be a number.
1260 * Before, After, Expp and Expt are the other args to this function and are
1261 * -1 if they are missing value.
1265 #define Enlarge(Num,atleast) if (Num.size + (atleast) > Num.max) { \
1266 char *new = MallocTSD(Num.size + (atleast) + 5); \
1267 Num.max = Num.size + (atleast) + 5; \
1268 memcpy(new,Num.num,Num.size); \
1275 int ShowExp
,Exponent
,ExponentLen
= 0,Afters
,Sign
,Point
,OrigExpp
,h
;
1277 char ExponentBuffer
[80]; /* enough even on a 256-bit-machine for an int */
1283 return(str_format_orig(TSD
, input
, Before
, After
, Expp
, Expt
));
1285 /* Convert the input to a number and check if it is a number at all. */
1286 if (getdescr(TSD
,input
,&mt
->fdescr
))
1287 exiterror(ERR_INCORRECT_CALL
, 11, "FORMAT", 1, tmpstr_of(TSD
, input
));
1289 /* Round the number according to NUMERIC DIGITS */
1290 str_round( &mt
->fdescr
, TSD
->currlevel
->currnumsize
) ;
1292 /* We have done the "call CheckArgs" of the ANSI function. */
1294 /* In the simplest case the first is the only argument. */
1295 if ((Before
== -1) && (After
== -1) && (Expp
== -1) && (Expt
== -1))
1296 return str_norm(TSD
, &mt
->fdescr
, NULL
);
1299 Expt
= TSD
->currlevel
->currnumsize
;
1301 /* The number is already set up but check twice that we don't have leading
1304 /*str_strip(&mt->fdescr); FGC: FIX: commented off for testing purpose */
1306 /* Trailing zeros are confusing, too: */
1307 while ((mt
->fdescr
.size
> 1) && (mt
->fdescr
.num
[mt
->fdescr
.size
- 1] == '0'))
1309 /* The number is normalized, now.
1310 * Usage of the variables:
1311 * mt->fdescr.num: Mantissa in the ANSI-standard and defined as usual, zeros
1312 * may be padded at the end but never at the start because:
1313 * mt->fdescr.exp: true exponent for the mantissa.
1314 * Exponent: Used Exponent for the mantissa, e.g.:
1315 * mt->fdescr.num=1,mt->fdescr.exp=2 = 0.1E2 = 10E0
1316 * In this case Exponent may be 0 to reflect the exponent we
1318 * Point: Defined in the standard but not used. It is obviously
1319 * equal to (mt->fdescr.exp-Exponent)
1320 * examples with both mt->fdescr.num=Mantissa="101" and mt->fdescr.exp=-2:
1321 * Exponent=0: output may be "0.00101"
1322 * Exponent=-3: output may be "1.01E-3"
1325 Exponent
= mt
->fdescr
.exp
;
1326 Sign
= (mt
->fdescr
.negative
) ? 1 : 0;
1327 /* Sign, Mantissa(mt->fdescr.num) and Exponent now reflect the Number.
1328 Keep in mind that the Mantissa of a num_descr is always normalized to
1329 a value smaller than 1. Thus, mt->fdescr(num=1,exp=1) means 0.1E1=1)
1332 /* Decide whether exponential form to be used, setting ShowExp.
1333 These tests have to be on the number before any rounding since
1334 decision on whether to have exponent affects what digits surround
1336 Only after this decision can Before and After arguments be checked.
1339 /* There is a test about maximum number of digits in the part before
1340 the decimal point, if non-exponential is to be used.
1341 eg 123.4E+3 becomes 1234E+2 by point removal, 123400 non-floating
1343 if (Exponent
> Expt
)
1345 /* Also a test on digits after the point.
1346 If the Exponent is negative at this point in the calculation there
1347 is a possibility that the non-exponential form would have too many
1348 zeros after the decimal point.
1349 For classic this test is:
1351 if (mt
->ClassicFormat
)
1353 if ((-(Exponent
- mt
->fdescr
.size
) > 2*Expt
) && (-Exponent
>= 0))
1356 else /* For modern it is: */
1358 /* The non-exponential value needs to be at least a millionth. */
1362 /* An over-riding rule for exponential form: */
1366 /* ShowExp now indicates whether to show an exponent. */
1369 /* Construct the exponential part of the result.
1370 Exponent at this point in the calculation reflects an integer
1371 mantissa. It has to be changed to reflect a decimal point at
1372 Point from the left. */
1373 /* set the Point to 1 as required for 'SCIENTIFIC': */
1376 if ((TSD
->currlevel
->numform
== NUM_FORM_ENG
) && h
)
1378 if (h
< 0) /* integer division may return values < 0 */
1380 Enlarge(mt
->fdescr
,h
);
1381 memset(mt
->fdescr
.num
+ mt
->fdescr
.size
,'0',h
);
1382 mt
->fdescr
.size
+= h
;
1386 else /* Force the exponent to zero for non-exponential format. */
1388 if (Exponent
> mt
->fdescr
.size
)
1390 Enlarge(mt
->fdescr
,Exponent
- mt
->fdescr
.size
);
1391 memset(mt
->fdescr
.num
+ mt
->fdescr
.size
,'0',Exponent
- mt
->fdescr
.size
);
1392 mt
->fdescr
.size
= Exponent
; /* mt->fdescr.size += Exponent - mt->fdescr.size; */
1394 /* else add zeros at the start of the Mantissa in the standard */
1396 /* Now Exponent is Zero and Mantissa with Point reflects Number */
1399 /* Deal with right of decimal point first since that can affect the
1400 left. Ensure the requested number of digits there.
1402 Afters
= mt
->fdescr
.size
- (mt
->fdescr
.exp
- Exponent
);
1403 assert(Afters
>= 0);
1405 After
= Afters
; /* Note default. */
1406 /* Make Afters match the requested After */
1410 Enlarge(mt
->fdescr
,h
);
1411 memset(mt
->fdescr
.num
+ mt
->fdescr
.size
,'0',h
);
1412 mt
->fdescr
.size
+= h
;
1414 else if (Afters
> After
)
1416 /* Round by adding 5 at the right place. */
1417 h
= mt
->fdescr
.exp
- Exponent
+ After
;
1418 /* h == position of overflowed digit or < 0 if it doesn't exist */
1419 if (h
< 0) /* default it to zero, it's a special case of truncating */
1421 mt
->fdescr
.size
= 1;
1422 mt
->fdescr
.num
[0] = '0'; /* always enough space for one character */
1424 mt
->fdescr
.exp
= -After
+ 1; /* let the mantissa been filled up later */
1426 else if (mt
->fdescr
.num
[h
] >= '5')
1428 mt
->fdescr
.size
= h
;
1429 /* Just in this case the value may change significantly! We leave
1430 * the normal transcription of the standard here to do it faster
1431 * and maybe better. Keep in mind some problems with rounding and
1432 * the awful ENGINEERING format.
1434 for (--h
;h
>= 0;h
--)
1436 if (++mt
->fdescr
.num
[h
] <= '9')
1438 mt
->fdescr
.num
[h
] = '0';
1440 if (h
< 0) /* overflow! we have to add one in the front! */
1442 Enlarge(mt
->fdescr
,1);
1443 memmove(mt
->fdescr
.num
+ 1,mt
->fdescr
.num
,mt
->fdescr
.size
);
1445 mt
->fdescr
.num
[0] = '1';
1447 if ( (mt
->fdescr
.exp
- Exponent
> Expt
)
1448 && Expp
!= 0 ) /* bug 20000727-84858 */
1452 Exponent
= mt
->fdescr
.exp
- 1;
1454 if ((TSD
->currlevel
->numform
== NUM_FORM_ENG
) && h
)
1456 if (h
< 0) /* integer division may return values < 0 */
1462 for (h
= mt
->fdescr
.size
- 1;h
>= 0;h
--)
1464 if (mt
->fdescr
.num
[h
] != '0')
1466 else if (h
== 0) /* completely zero */
1469 /* The value itself is correct now but check the format: */
1471 else /* rounding by truncating */
1473 mt
->fdescr
.size
= h
;
1474 for (--h
;h
>= 0;h
--)
1476 if (mt
->fdescr
.num
[h
] != '0')
1478 else if (h
== 0) /* completely zero */
1483 /* That's all for now with the right part */
1485 /* Now deal with the part of the result before the decimal point. */
1486 Point
= mt
->fdescr
.exp
- Exponent
; /* Point doesn't change never more */
1488 if (h
<= 0) /* missing front of the number? */
1489 h
= 1; /* assume 1 char for "0" of "0.xxx" */
1491 Before
= h
+ Sign
; /* Note default. */
1492 /* Make Point match Before */
1493 if (h
> Before
- Sign
)
1494 exiterror(ERR_INCORRECT_CALL
, 38, "FORMAT", 2, tmpstr_of(TSD
, input
));
1496 /* We check the length of the exponent field, first. This allows to
1497 * allocate a sufficient string for the complete number.
1502 if ((h
= Exponent
) < 0)
1504 sprintf(ExponentBuffer
,"%d",h
);
1505 ExponentLen
= strlen(ExponentBuffer
);
1508 if (ExponentLen
> Expp
)
1509 exiterror(ERR_INCORRECT_CALL
, 38, "FORMAT", 4, tmpstr_of(TSD
, input
));
1512 Expp
= 0; /* don't format an exponent */
1514 bufsize
= Before
+ After
+ Expp
+ 4; /* Point, "E+", term. zero */
1515 buf
= MallocTSD(bufsize
);
1517 /* Now do the formatting, it's a little bit complicated, since the parts
1518 * of the number may not exist (partially).
1520 /* Format the part before the point */
1521 if (Point
<= 0) /* denormalized number */
1523 memset(buf
,' ',Before
- 1);
1524 buf
[Before
- 1] = '0';
1526 buf
[Before
- 2] = '-';
1530 assert(Point
<= mt
->fdescr
.size
); /* before part should always fit */
1531 memset(buf
,' ',Before
- Point
);
1532 memcpy(buf
+ Before
- Point
,mt
->fdescr
.num
,Point
);
1534 buf
[Before
- Point
- 1] = '-';
1538 /* Process the part after the decimal point */
1541 buf
[bufpos
++] = '.';
1543 { /* Denormalized mantissa, we must fill up with zeros */
1546 h
= After
; /* beware of an overrun */
1547 memset(buf
+ bufpos
,'0',h
);
1548 assert(After
- h
<= mt
->fdescr
.size
);
1549 memcpy(buf
+ bufpos
+ h
,mt
->fdescr
.num
,After
- h
);
1553 assert(Point
+ After
<= mt
->fdescr
.size
);
1554 memcpy(buf
+ bufpos
,mt
->fdescr
.num
+ Point
,After
);
1559 /* Finally process the exponent. ExponentBuffer contents the exponent
1568 memset(buf
+ bufpos
,' ',Expp
+ 2);
1574 buf
[bufpos
++] = 'E';
1575 buf
[bufpos
++] = (char) ((Exponent
< 0) ? '-' : '+');
1576 memset(buf
+ bufpos
,'0',Expp
- ExponentLen
);
1577 memcpy(buf
+ bufpos
+ Expp
- ExponentLen
,ExponentBuffer
,ExponentLen
);
1582 assert(bufpos
< bufsize
);
1585 retval
= Str_creTSD(buf
);
1596 streng
*str_norm( const tsd_t
*TSD
, num_descr
*in
, streng
*try )
1598 streng
*result
=NULL
;
1600 int i
=0, j
=0, k
=0, p
=0 ;
1601 int sdigs
=0, top
=0 ;
1607 IS_AT_LEAST( mt
->norm_out
, mt
->norm_outsize
, 3*TSD
->currlevel
->currnumsize
+5 ) ;
1609 mt
->outptr2
= mt
->norm_out
;
1613 mt
->norm_out
[k
++] = '-' ;
1615 /* remove effect of leading zeros in the descriptor */
1616 for ( i
=0; i
<in
->size
; i
++)
1618 if ( in
->num
[i
]!='0' )
1623 if (i
==in
->size
) /* mantissa contains zeros only */
1625 in
->size
= in
->exp
= 1 ;
1631 * Replace assert() with real code - MDW 30012002
1632 assert( try->max > 0 ) ;
1633 try->value[0] = '0' ;
1638 try->value
[0] = '0' ;
1643 Free_stringTSD( try ) ;
1644 try = Str_creTSD( "0" ) ;
1648 try = Str_creTSD( "0" ) ;
1654 if ((MAX_EXPONENT
+1<exp
) || ((-MAX_EXPONENT
-1)>exp
)) /* too late here! FGC */
1656 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1660 exp
-= top
= i
; /* adjust the exponent */
1662 /* Again, it is too late for an adjustment to digits() here. The user may
1663 * have changed digits() in between. The rounding should have taken place
1664 * after the math operation (which happens) and that's all.
1665 * Benefit: We don't have to round and therefore can't change the
1666 * exponent by rounding. FGC
1668 sdigs
= MIN( size
-i
, TSD
->currlevel
->currnumsize
) ; /* significant digits in answer */
1670 if ((exp
<= -6) || ( exp
> TSD
->currlevel
->currnumsize
)) /* ANSI */
1672 /* Too late for rounding, must be fixed! FGC */
1673 if ((size
-i
> TSD
->currlevel
->currnumsize
) && (in
->num
[TSD
->currlevel
->currnumsize
+i
] > '4'))
1675 for (j
=TSD
->currlevel
->currnumsize
+i
-1; j
>=i
; j
--)
1677 if (((in
->num
[j
])++)=='9')
1689 frst
= mt
->norm_out
[k
++] = (char) (( i
<size
) ? in
->num
[i
++] : '0') ;
1690 if (i
<size
&& (1<=TSD
->currlevel
->currnumsize
-(frst
!='0')))
1691 mt
->norm_out
[k
++] = '.' ;
1693 for (j
=1; (i
<size
) && (j
<=TSD
->currlevel
->currnumsize
-(frst
!='0')); j
++ )
1694 mt
->norm_out
[k
++] = in
->num
[i
++] ;
1698 mt
->norm_out
[k
++] = 'E' ;
1699 sprintf( &mt
->norm_out
[k
], "%+d", j
) ;
1701 return Str_creTSD( mt
->norm_out
) ;
1706 mt
->norm_out
[k
++] = '0' ;
1709 mt
->norm_out
[k
++] = '.' ;
1710 for ( j
=0; j
>exp
; j
-- )
1711 mt
->norm_out
[k
++] = '0' ;
1715 top
= MIN( sdigs
, TSD
->currlevel
->currnumsize
) + i
;
1716 if ((size
-i
> TSD
->currlevel
->currnumsize
) && (in
->num
[TSD
->currlevel
->currnumsize
+i
] > '4'))
1718 /* Too late for rounding, must be fixed! FGC */
1719 for (j
=TSD
->currlevel
->currnumsize
+i
-1; j
>=i
; j
--)
1721 if (((in
->num
[j
])++)=='9')
1729 p
+= mt
->norm_out
[k
++] = '1' ;
1737 mt
->norm_out
[k
++] = '.' ;
1739 p
+= (mt
->norm_out
[k
++] = in
->num
[i
]) - '0' ;
1741 while (j
-- > 0) /* Fill possibly lost zeros */
1742 mt
->norm_out
[k
++] = '0';
1745 mt
->norm_out
[(k
=1)-1] = '0' ;
1753 result
= Str_makeTSD( k
) ;
1754 Free_stringTSD( try ) ;
1758 result
= Str_makeTSD( k
) ;
1760 memcpy( result
->value
, mt
->norm_out
, result
->len
=k
) ;
1767 streng
*str_norm( const tsd_t
*TSD
, num_descr
*in
, streng
*try )
1769 streng
*result
=NULL
;
1771 int i
=0, j
=0, k
=0, p
=0 ;
1772 int sdigs
=0, top
=0 ;
1773 int exp
=0, size
=0, neg
=0 ;
1778 IS_AT_LEAST( mt
->norm_out
, mt
->norm_outsize
, 3*TSD
->currlevel
->currnumsize
+5 ) ;
1780 mt
->outptr2
= mt
->norm_out
;
1784 mt
->norm_out
[k
++] = '-' ;
1786 /* remove effect of leading zeros in the descriptor */
1787 for ( i
=0; i
<in
->size
; i
++)
1789 if ( in
->num
[i
]!='0' )
1794 neg
= in
->negative
;
1796 size
= exp
= neg
= 0 ;
1798 if ((MAX_EXPONENT
+1<exp
) || ((-MAX_EXPONENT
)-1>exp
))
1799 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
1801 exp
-= top
= i
; /* adjust the exponent */
1802 sdigs
= MIN(size
-i
,TSD
->currlevel
->currnumsize
); /* significant digits in answer */
1804 if (( sdigs
- exp
> 2*TSD
->currlevel
->currnumsize
) || ( sdigs
< exp
))
1807 if ((size
-i
> TSD
->currlevel
->currnumsize
) && (in
->num
[TSD
->currlevel
->currnumsize
+i
] > '4'))
1809 for (j
=TSD
->currlevel
->currnumsize
+i
-1; j
>=i
; j
--)
1811 if (((in
->num
[j
])++)=='9')
1824 frst
= mt
->norm_out
[k
++] = ( i
<size
) ? in
->num
[i
++] : '0' ;
1826 mt
->norm_out
[k
++] = '.' ;
1828 for (j
=1; (i
<size
) && (j
<=TSD
->currlevel
->currnumsize
-(frst
!='0')); j
++ )
1829 mt
->norm_out
[k
++] = in
->num
[i
++] ;
1833 mt
->norm_out
[k
++] = 'E' ;
1834 sprintf( &mt
->norm_out
[k
], "%+d", j
) ;
1836 return Str_creTSD( mt
->norm_out
) ;
1841 mt
->norm_out
[k
++] = '0' ;
1844 mt
->norm_out
[k
++] = '.' ;
1845 for ( j
=0; j
>exp
; j
-- )
1846 mt
->norm_out
[k
++] = '0' ;
1850 top
= MIN( sdigs
, TSD
->currlevel
->currnumsize
) + i
;
1851 if ((size
-i
> TSD
->currlevel
->currnumsize
) && (in
->num
[TSD
->currlevel
->currnumsize
+i
] > '4'))
1853 for (j
=TSD
->currlevel
->currnumsize
+i
-1; j
>=i
; j
--)
1855 if (((in
->num
[j
])++)=='9')
1863 p
+= mt
->norm_out
[k
++] = '1' ;
1871 mt
->norm_out
[k
++] = '.' ;
1873 p
+= (mt
->norm_out
[k
++] = in
->num
[i
]) - '0' ;
1876 mt
->norm_out
[(k
=1)-1] = '0' ;
1884 result
= Str_makeTSD( k
) ;
1885 Free_stringTSD( try ) ;
1889 result
= Str_makeTSD( k
) ;
1891 memcpy( result
->value
, mt
->norm_out
, result
->len
=k
) ;
1899 int string_test( const tsd_t
*TSD
, const num_descr
*first
, const num_descr
*second
)
1901 int i
=0, top
=0, fnul
=0, snul
=0 ;
1902 char fchar
=' ', schar
=' ' ;
1904 if ( first
->negative
!= second
->negative
) /* have different signs */
1905 return ( first
->negative
? -1 : 1 ) ;
1907 fnul
= ( first
->size
==1 && first
->exp
==1 && first
->num
[0]=='0') ;
1908 snul
= ( second
->size
==1 && second
->exp
==1 && second
->num
[0]=='0') ;
1911 if (fnul
&& snul
) return 0 ;
1912 if (fnul
) return (second
->negative
? 1 : -1 ) ;
1913 else return (first
->negative
? -1 : 1 ) ;
1916 if ( first
->exp
!= second
->exp
) /* have different order */
1917 return (log_xor( first
->negative
, first
->exp
>second
->exp
) ? 1 : -1 ) ;
1919 /* same order and sign, have to compare TSD->currlevel->currnumsize-TSD->currlevel->numfuzz first */
1920 top
= MIN( TSD
->currlevel
->currnumsize
-TSD
->currlevel
->numfuzz
, MAX( first
->size
, second
->size
)) ;
1921 for ( i
=0; i
<top
; i
++ )
1923 fchar
= (char) ((first
->size
> i
) ? first
->num
[i
] : '0') ;
1924 schar
= (char) ((second
->size
> i
) ? second
->num
[i
] : '0') ;
1925 if ( fchar
!= schar
)
1926 return log_xor( first
->negative
, fchar
>schar
) ? 1 : -1 ;
1929 /* hmmm, last resort: can the numbers be rounded to make a difference */
1930 fchar
= (char) ((first
->size
> i
) ? first
->num
[i
] : '0') ;
1931 schar
= (char) ((second
->size
> i
) ? second
->num
[i
] : '0') ;
1932 if (((fchar
>'4') && (schar
>'4')) || ((fchar
<'5') && (schar
<'5')))
1933 return 0 ; /* equality! */
1935 /* now, one is rounded upwards, the other downwards */
1936 return log_xor( first
->negative
, fchar
>'5' ) ? 1 : -1 ;
1941 num_descr
*string_incr( const tsd_t
*TSD
, num_descr
*input
)
1946 assert( input
->size
> 0 ) ;
1948 if (input
->size
!= input
->exp
|| input
->exp
>= TSD
->currlevel
->currnumsize
)
1950 static const num_descr one
= { "1", 0, 1, 1, 1 } ;
1952 string_add( TSD
, input
, &one
, input
) ;
1953 str_round(input
,TSD
->currlevel
->currnumsize
) ;
1958 last
= input
->size
-1 ;
1962 if (input
->negative
)
1964 if (cptr
[last
] > '1')
1969 else if (cptr
[last
]=='1')
1973 str_strip( input
) ;
1978 assert( cptr
[last
] == '0' ) ;
1980 cptr
[last
--] = '9' ;
1985 if (cptr
[last
] < '9')
1992 assert( cptr
[last
] == '9' ) ;
1993 cptr
[last
--] = '0' ;
1999 if (input
->size
>= input
->max
)
2003 assert( input
->size
== input
->max
) ;
2004 new = MallocTSD( input
->max
* 2 + 2 ) ;
2005 memcpy( new+1, input
->num
, input
->size
) ;
2009 input
->max
= input
->max
*2 + 2 ;
2010 FreeTSD( input
->num
) ;
2011 cptr
= input
->num
= new ;
2015 memmove( input
->num
+1, input
->num
, input
->size
) ;
2018 input
->num
[0] = '0' ;
2027 void string_div( const tsd_t
*TSD
, const num_descr
*f
, const num_descr
*s
, num_descr
*r
, num_descr
*r2
, int type
)
2029 int ssize
=0, tstart
=0, tcnt
=0, finished
=0, tend
=0 ;
2030 int i
=0, cont
=0, outp
=0, test
=0, loan
=0 ;
2031 int origneg
=0, origexp
=0 ;
2036 IS_AT_LEAST( mt
->div_out
, mt
->div_outsize
, (TSD
->currlevel
->currnumsize
+1)*2+1 ) ;
2037 IS_AT_LEAST( r
->num
, r
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
2039 mt
->outptr3
= mt
->div_out
;
2042 ssize
= MIN( s
->size
, TSD
->currlevel
->currnumsize
+1 ) ;
2043 r
->exp
= 1 + f
->exp
- s
->exp
;
2044 r
->negative
= log_xor( f
->negative
, s
->negative
) ;
2046 /* initialize the pointers */
2048 tend
= tstart
+ MIN( f
->size
, TSD
->currlevel
->currnumsize
+1 ) ;
2050 /* first, fill out tmp to the size of ssize */
2051 for (tcnt
=tstart
; tcnt
< ssize
; tcnt
++ )
2052 mt
->div_out
[tcnt
] = (char) ((tcnt
<tend
) ? f
->num
[tcnt
] : '0') ;
2054 /* if the ssize first digits in f->num form a number which is smaller */
2055 /* than s->num, we must add an additional digit to f->num */
2057 for (i
=0; i
<ssize
; i
++)
2059 if ( mt
->div_out
[i
] > s
->num
[i
] )
2061 else if ( mt
->div_out
[i
] < s
->num
[i
] )
2063 mt
->div_out
[tcnt
] = (char) ((tcnt
<tend
) ? f
->num
[tcnt
] : '0') ;
2070 /* situation: s->num[1..ssize] contains the devisor, and the array */
2071 /* div_out[tstart==0..tcnt-1] hold the (first part of the) devidend. The */
2072 /* array f->num[tcnt..tend-1] (which may be empty) holds the last */
2073 /* part of the devidend */
2075 /* then foreach resulting digit we want */
2076 for (outp
=0; outp
<TSD
->currlevel
->currnumsize
+1 && !finished
; outp
++)
2078 r
->num
[outp
] = '0' ;
2079 if ((tcnt
-tstart
> ssize
) && (mt
->div_out
[tstart
]=='0'))
2082 /* if this is integer division, and we have hit the decimal point... */
2083 if ((type
!=DIVTYPE_NORMAL
) && (outp
>=r
->exp
))
2089 /* try to subtract as many times as possible */
2090 for (cont
=1; cont
; )
2092 /* can we subtract one more time? */
2093 if (tcnt
-tstart
== ssize
)
2094 for (i
=0; i
<ssize
; i
++ )
2096 test
= mt
->div_out
[tstart
+i
] - s
->num
[i
] ;
2103 /* if we can continue, subtract it */
2108 for (i
=0; i
<ssize
; i
++)
2110 /* When do M$ ever build usable compilers, sigh: */
2111 char h
= (char) ( s
->num
[ssize
-1-i
] - '0' + loan
) ;
2112 mt
->div_out
[tcnt
-1-i
] = (char) (mt
->div_out
[tcnt
-1-i
] - h
);
2113 if ((loan
= (mt
->div_out
[tcnt
-1-i
] < '0'))!=0)
2114 mt
->div_out
[tcnt
-1-i
] += 10 ;
2118 /* decrement it and check for '0' */
2119 mt
->div_out
[tstart
] -= 1 ;
2120 if ((tcnt
-tstart
> ssize
) && (mt
->div_out
[tstart
]=='0'))
2125 } /* for each possible subtraction */
2127 if ((tcnt
-tstart
> ssize
) && (mt
->div_out
[tstart
]=='0'))
2130 /* do we have anything left of the devidend, only meaningful if */
2131 /* all digits in original divident have been processed, it is */
2132 /* also safe to assume that divident and devisor have equal size */
2134 assert( tcnt
-tstart
== ssize
) ;
2135 mt
->div_out
[tcnt
] = (char) ((tcnt
<tend
) ? f
->num
[tcnt
] : '0') ;
2139 for (i
=tstart
; i
<tcnt
; i
++)
2141 if (mt
->div_out
[i
]!='0')
2149 } /* for each digit wanted in the result */
2152 origneg
= f
->negative
;
2154 if (type
==DIVTYPE_BOTH
) /* return both answers */
2156 IS_AT_LEAST( r2
->num
, r2
->max
, outp
) ;
2158 memcpy(r2
->num
, r
->num
, outp
) ;
2159 r2
->negative
= r
->negative
;
2160 r2
->size
= r
->size
;
2163 for (r2
->size
= outp
; (r2
->size
> r2
->exp
) && (r2
->size
> 1); r2
->size
--)
2165 if (r2
->num
[r2
->size
-1]!='0')
2170 if ((type
== DIVTYPE_REMINDER
) || (type
== DIVTYPE_BOTH
))
2172 /* we are really interested in the reminder, so swap things */
2173 for (i
=0; i
<MIN(MAX(tend
,tcnt
)-tstart
,TSD
->currlevel
->currnumsize
+1); i
++ )
2174 r
->num
[i
] = (char) (i
<tcnt
-tstart
? mt
->div_out
[tstart
+i
] : f
->num
[tstart
+i
]) ;
2176 r
->size
= outp
= i
;
2177 r
->exp
= origexp
- tstart
;
2178 r
->negative
= origneg
;
2181 /* then, at the end, we have to strip of trailing zeros that come */
2182 /* after the decimal point, first do we have any decimals? */
2183 for (r
->size
= outp
; (r
->size
> r
->exp
) && (r
->size
> 1); r
->size
--)
2185 if (r
->num
[r
->size
-1]!='0')
2193 /* The multiplication table for two single-digits numbers */
2194 static const char mult
[10][10][3] = {
2195 { "00", "00", "00", "00", "00", "00", "00", "00", "00", "00" },
2196 { "00", "01", "02", "03", "04", "05", "06", "07", "08", "09" },
2197 { "00", "02", "04", "06", "08", "10", "12", "14", "16", "18" },
2198 { "00", "03", "06", "09", "12", "15", "18", "21", "24", "27" },
2199 { "00", "04", "08", "12", "16", "20", "24", "28", "32", "36" },
2200 { "00", "05", "10", "15", "20", "25", "30", "35", "40", "45" },
2201 { "00", "06", "12", "18", "24", "30", "36", "42", "48", "54" },
2202 { "00", "07", "14", "21", "28", "35", "42", "49", "56", "63" },
2203 { "00", "08", "16", "24", "32", "40", "48", "56", "64", "72" },
2204 { "00", "09", "18", "27", "36", "45", "54", "63", "72", "81" },
2208 void string_mul( const tsd_t
*TSD
, const num_descr
*f
, const num_descr
*s
, num_descr
*r
)
2211 const char *answer
=NULL
;
2212 int i
=0, sskip
=0, fskip
=0, sstart
=0, fstart
=0, base
=0, offset
=0, carry
=0, j
=0 ;
2217 IS_AT_LEAST( mt
->mul_out
, mt
->mul_outsize
, 2*(TSD
->currlevel
->currnumsize
+1) ) ;
2219 mt
->outptr4
= mt
->mul_out
;
2222 for (i
=0; i
<2*(TSD
->currlevel
->currnumsize
+1); mt
->mul_out
[i
++]='0') ;
2223 outp
= &mt
->mul_out
[2*(TSD
->currlevel
->currnumsize
+1)-1] ;
2225 for (sskip
=0; (sskip
<s
->size
) && (s
->num
[sskip
]=='0'); sskip
++ ) ;
2226 sstart
= MIN( sskip
+TSD
->currlevel
->currnumsize
+1, s
->size
-1 ) ;
2228 for (fskip
=0; (fskip
<f
->size
) && (f
->num
[fskip
]=='0'); fskip
++ ) ;
2229 fstart
= MIN( fskip
+TSD
->currlevel
->currnumsize
+1, f
->size
-1 ) ;
2231 base
= 2*(TSD
->currlevel
->currnumsize
+1)-1 ;
2232 offset
= carry
= 0 ;
2233 for ( i
=sstart
; i
>=sskip
; i
-- )
2235 offset
= carry
= 0 ;
2236 assert( base
>= 0 ) ;
2237 for ( j
=fstart
; j
>=fskip
; j
-- )
2239 answer
= mult
[f
->num
[j
]-'0'][s
->num
[i
]-'0'] ;
2240 assert( base
-offset
>= 0 ) ;
2241 /* Stupid MSVC likes this only: */
2242 mt
->mul_out
[base
-offset
] = (char) (mt
->mul_out
[base
-offset
] +
2243 answer
[1] - '0' + carry
) ;
2244 carry
= answer
[0] - '0' ;
2245 for (; mt
->mul_out
[base
-offset
]>'9'; )
2247 mt
->mul_out
[base
-offset
] -= 10 ;
2252 if (base
-offset
>= 0)
2253 mt
->mul_out
[base
-offset
++] = (char) (carry
+ '0') ;
2255 exiterror( ERR_INTERPRETER_FAILURE
, 1, __FILE__
, __LINE__
, "" ) ;
2260 IS_AT_LEAST( r
->num
, r
->max
, /*2*(TSD->currlevel->currnumsize+1)*/
2261 outp
-mt
->mul_out
-base
+offset
) ;
2263 for (i
=base
-offset
+2; (i
<=outp
-mt
->mul_out
); i
++ )
2264 r
->num
[j
++] = mt
->mul_out
[i
] ;
2272 r
->exp
= s
->exp
+ f
->exp
;
2274 r
->negative
= log_xor( f
->negative
, s
->negative
) ;
2276 str_round( r
, TSD
->currlevel
->currnumsize
) ;
2280 static void descr_strip( const tsd_t
*TSD
, const num_descr
*from
, num_descr
*to
)
2284 IS_AT_LEAST( to
->num
, to
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
2286 to
->negative
= from
->negative
;
2287 for (i
=0; (i
<from
->size
) && (from
->num
[i
]=='0'); i
++ ) ;
2288 to
->exp
= from
->exp
- i
;
2289 for (j
=0; j
+i
<from
->size
; j
++ )
2290 to
->num
[j
] = from
->num
[i
+j
] ;
2292 if ((to
->exp
-1 > MAX_EXPONENT
) || ( -MAX_EXPONENT
> to
->exp
+1))
2293 exiterror( ERR_ARITH_OVERFLOW
, 0 ) ;
2300 void string_pow( const tsd_t
*TSD
, const num_descr
*num
, int power
, num_descr
*acc
, num_descr
*res
)
2302 static const num_descr one
= { "1", 0, 1, 1, 2 } ;
2303 int ineg
=0, pow
=0, cnt
=0 ;
2305 IS_AT_LEAST( res
->num
, res
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
2306 IS_AT_LEAST( acc
->num
, acc
->max
, TSD
->currlevel
->currnumsize
+1 ) ;
2320 for (cnt
=0; pow
; cnt
++ )
2325 if (power
& (1<<(cnt
-1)))
2327 /* multiply acc with *f, and put answer into acc */
2328 string_mul( TSD
, acc
, num
, res
) ;
2329 assert( acc
->size
<= acc
->max
&& res
->size
<= res
->max
) ;
2330 descr_strip( TSD
, res
, acc
) ;
2331 assert( acc
->size
<= acc
->max
&& res
->size
<= res
->max
) ;
2335 break ; /* horrible example of dataflow */
2337 /* then, square the contents of acc */
2338 string_mul( TSD
, acc
, acc
, res
) ;
2339 assert( acc
->size
<= acc
->max
&& res
->size
<= res
->max
) ;
2340 descr_strip( TSD
, res
, acc
) ;
2341 assert( acc
->size
<= acc
->max
&& res
->size
<= res
->max
) ;
2345 /* may hang if acc==zero ? */
2346 string_div( TSD
, &one
, acc
, res
, NULL
, DIVTYPE_NORMAL
) ;
2348 descr_strip( TSD
, acc
, res
) ;
2349 assert( acc
->size
<= acc
->max
&& res
->size
<= res
->max
) ;
2353 /* ========= interface routines to the arithmetic routines ========== */
2355 streng
*str_add( const tsd_t
*TSD
, const void *descr
, const streng
*second
)
2360 if (getdescr( TSD
, second
, &mt
->sdescr
))
2361 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2363 string_add( TSD
, descr
, &mt
->sdescr
, &mt
->rdescr
) ;
2364 return str_norm( TSD
, &mt
->rdescr
, NULL
) ;
2367 int descr_sign( const void *descr
)
2369 return( ((num_descr
*)descr
)->negative
? -1 : 1 ) ;
2373 void free_a_descr( const tsd_t
*TSD
, num_descr
*in
)
2375 assert( in
->size
<= in
->max
) ;
2378 FreeTSD( in
->num
) ;
2384 num_descr
*get_a_descr( const tsd_t
*TSD
, const streng
*num
)
2386 num_descr
*descr
=NULL
;
2388 descr
=MallocTSD( sizeof(num_descr
)) ;
2392 if (getdescr( TSD
, num
, descr
))
2393 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2395 return (void*)descr
;
2399 int str_true( const tsd_t
*TSD
, const streng
*input
)
2404 if (input
->len
!= 1)
2405 exiterror( ERR_UNLOGICAL_VALUE
, 0 ) ;
2407 switch (input
->value
[0])
2414 exiterror( ERR_UNLOGICAL_VALUE
, 0 ) ;
2417 /* Too keep the compiler happy */
2422 streng
*str_abs( const tsd_t
*TSD
, const streng
*input
)
2427 if (getdescr(TSD
,input
,&mt
->fdescr
))
2428 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2430 mt
->fdescr
.negative
= 0 ;
2431 return str_norm( TSD
, &mt
->fdescr
, NULL
) ;
2435 streng
*str_trunc( const tsd_t
*TSD
, const streng
*number
, int deci
)
2437 int i
=0, j
=0, k
=0, size
=0, top
=0 ;
2438 streng
*result
=NULL
;
2443 /* first, convert number to internal representation */
2444 if (getdescr( TSD
, number
, &mt
->fdescr
))
2445 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2447 /* get rid of possible excessive precision */
2448 if (mt
->fdescr
.size
>TSD
->currlevel
->currnumsize
)
2449 str_round( &mt
->fdescr
, TSD
->currlevel
->currnumsize
) ;
2451 /* who big must the result string be? */
2452 if ((i
=mt
->fdescr
.exp
) > 0 )
2453 size
= mt
->fdescr
.exp
+ deci
;
2458 * Adrian Sutherland <adrian@dealernet.co.uk>
2459 * Changed the following line from '+ 2' to '+ 3',
2460 * because I was getting core dumps ... I think that we need this
2461 * because negative numbers BIGGER THAN -1 need a sign, a zero and
2462 * a decimal point ... A.
2464 result
= Str_makeTSD( size
+ 3 ) ; /* allow for sign and decimal point */
2467 if (mt
->fdescr
.negative
)
2468 result
->value
[j
++] = '-' ;
2470 /* first fill in the known numerals of the integer part */
2471 top
= MIN( mt
->fdescr
.exp
, mt
->fdescr
.size
) ;
2472 for (i
=0; i
<top
; i
++)
2473 result
->value
[j
++] = mt
->fdescr
.num
[i
] ;
2475 /* pad out with '0' in the integer part, if necessary */
2476 for (k
=i
; k
<mt
->fdescr
.exp
; k
++)
2477 result
->value
[j
++] = '0' ;
2480 result
->value
[j
++] = '0' ;
2485 result
->value
[j
++] = '.' ;
2487 /* pad with zeros between decimal point and number */
2488 for (k
=0; k
>mt
->fdescr
.exp
; k
--)
2489 result
->value
[j
++] = '0' ;
2492 /* fill in with the decimals, if any */
2493 top
= MIN( mt
->fdescr
.size
-mt
->fdescr
.exp
, deci
) + i
+ k
;
2495 result
->value
[j
++] = mt
->fdescr
.num
[i
] ;
2497 /* pad with zeros if necessary */
2498 for (; i
<deci
+MIN(mt
->fdescr
.exp
,mt
->fdescr
.size
); i
++ )
2499 result
->value
[j
++] = '0' ;
2502 assert( (result
->len
<= result
->max
) && (result
->len
<=size
+2) ) ;
2508 /* ------------------------------------------------------------------
2509 * This function converts a packed binary string to a decimal integer.
2510 * It is equivalent of interpreting the binary string as a number of
2511 * base 256, and converting it to base 10 (the actual algorithm uses
2512 * a number of base 2, padded to a multiple of 8 digits). Negative
2513 * numbers are interpreted as two's complement.
2515 * First parameter is the packed binary string; second parameter is
2516 * the number of initial characters to skip (i.e. the position of the
2517 * most significant byte in 'input'; the third parameter is a boolean
2518 * telling if this number is signed or not.
2520 * The significance of the 'too_large' variable: If the number has
2521 * leading zeros, that is not an error, so the 'fdescr' might be set
2522 * to values larger than it can hold. However, the error occurs only
2523 * if that value is used. Therefore, if 'fdescr' becomes bigger than
2524 * the max whole number, 'too_large' is set. If attempts are made to
2525 * use 'fdescr' while 'too_large' is set, an error occurs.
2527 * Note that this algoritm requires that string_mul and string_add
2528 * does not change anything in their first two parameters.
2530 * The 'input' variable is assumed to have at least one digit, so don't
2531 * call this function with a null string. Maybe the compiler could
2532 * optimize this function better if [esf]descr were locals?
2535 streng
*str_digitize( const tsd_t
*TSD
, const streng
*input
, int start
, int sign
)
2537 int cur_byte
=0 ; /* current byte in 'input' */
2538 int cur_bit
=0 ; /* current bit in 'input' */
2539 int too_large
=0 ; /* error flag (see above) */
2544 /* do we have anything to work on? */
2545 assert( start
< Str_len(input
) ) ;
2547 /* ensure that temporary number descriptors has enough space */
2548 IS_AT_LEAST( mt
->fdescr
.num
, mt
->fdescr
.max
, TSD
->currlevel
->currnumsize
+2 ) ;
2549 IS_AT_LEAST( mt
->edescr
.num
, mt
->edescr
.max
, TSD
->currlevel
->currnumsize
+2 ) ;
2550 IS_AT_LEAST( mt
->sdescr
.num
, mt
->sdescr
.max
, TSD
->currlevel
->currnumsize
+2 ) ;
2553 * Initialize the temporary number descriptors: 'fdescr', 'sdescr'
2554 * and 'edescr'. They will be initialized to 0, 1 and 2 respectively.
2555 * They are used for:
2557 * fdescr: contains the value of the current bit of the current
2558 * byte, e.g the third last bit in the last byte will
2559 * have the value '0100'b (=4). This value is multiplied
2560 * with two at each iteration of the inner loop. Is
2561 * initialized to the value '1', and will have the same
2564 * sdescr: contains '2', to make doubling of 'fdescr' easy
2566 * edescr: contains the answer, initially set to '0' if 'input'
2567 * is positive, or '-1' if 'input' is negative. The
2568 * descriptor 'fdescr' is added to (or implicitly
2569 * subtracted from) this number.
2571 mt
->fdescr
.size
= mt
->sdescr
.size
= mt
->edescr
.size
= 1 ;
2572 mt
->fdescr
.negative
= mt
->sdescr
.negative
= mt
->edescr
.negative
= 0 ;
2573 mt
->fdescr
.exp
= mt
->sdescr
.exp
= mt
->edescr
.exp
= 1 ;
2575 mt
->edescr
.num
[0] = '0' ; /* the resulting number */
2576 mt
->fdescr
.num
[0] = '1' ; /* the value of each binary digit */
2577 mt
->sdescr
.num
[0] = '2' ; /* the number to multiply 'fdescr' in */
2580 * If 'input' is signed, but positive, treat as if it was unsigned.
2581 * 'sign' is then effectively a boolean stating whether 'input' is
2582 * a negative number. In that case, 'edescr' should be set to '-1'.
2583 * Also, 'fdescr' is set to negative, so that it is subtracted from
2584 * 'edescr' when given to string_add().
2588 if (input
->value
[start
] & 0x80)
2590 mt
->edescr
.num
[0] = '1' ;
2591 mt
->edescr
.negative
= 1 ;
2592 mt
->fdescr
.negative
= 1 ;
2599 * Each iteration of the outer loop will process a byte in 'input',
2600 * starting with the last (least significant) byte. Each iteration
2601 * of the inner loop will process one bit in the byte currently
2602 * processed by the outer loop.
2604 for (cur_byte
=Str_len(input
)-1; cur_byte
>=start
; cur_byte
--)
2606 for (cur_bit
=0; cur_bit
<8; cur_bit
++)
2608 /* does the precision hold? if not, set flag */
2609 if (mt
->fdescr
.size
> TSD
->currlevel
->currnumsize
)
2613 * If the current bit (the j'th bit in the i'th byte) is set
2614 * and input is positive; or if current bit is not set and
2615 * input is negative, then increase the value of the result.
2616 * This is not really a bitwise xor, but a logical xor, but
2617 * the values are always 1 or 0, so it doesn't matter.
2619 if ((sign
) ^ ((input
->value
[cur_byte
] >> cur_bit
) & 1))
2622 exiterror( ERR_INVALID_INTEGER
, 0 ) ;
2624 string_add( TSD
, &mt
->edescr
, &mt
->fdescr
, &mt
->edescr
) ;
2628 * Str_ip away any leading zeros. If this is not done, the
2629 * accuracy of the operation will deter, since string_add()
2630 * return answer with leading zero, and the accumulative
2631 * effect of this would make 'edescr' zero after a few
2632 * iterations of the loop.
2634 str_strip( &mt
->edescr
) ;
2637 * Increase the value of 'fdescr', so that it corresponds with
2638 * the significance of the current bit in 'input'. But don't
2639 * do this if 'fdescr' isn't capable of holding that number.
2643 string_mul( TSD
, &mt
->fdescr
, &mt
->sdescr
, &mt
->fdescr
) ;
2644 str_strip( &mt
->fdescr
) ;
2649 /* normalize answer and return to caller */
2650 return str_norm( TSD
, &mt
->edescr
, NULL
) ;
2653 streng
*str_binerize( const tsd_t
*TSD
, const streng
*number
, int length
)
2656 streng
*result
=NULL
;
2657 char *res_ptr
=NULL
;
2660 * We are going to need two number in this algoritm, so we can
2661 * just as well make them right away. We could initialize these on
2662 * the first invocation of this routine, and thereby saving some
2663 * space, but that would 1) take CPU on every invocation; 2) it
2664 * would probably cost just as much space in the text segment.
2665 * (Would have to set NUMERIC DIGIT to at least 4 before calling
2666 * getdescr with these.)
2668 static const num_descr minus_one
= { "1", 1, 1, 1, 2 } ;
2669 static const num_descr byte
= { "256", 0, 3, 3, 4 } ;
2676 * First, let us convert the number into a descriptor. If that is
2677 * not possible, then we don't have a number, which is an error.
2679 if (getdescr( TSD
, number
, &mt
->edescr
))
2680 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2683 * If the number is negative, then we *must* know how long it is,
2684 * since we are going to pad with 'ff'x bytes at the left up the
2685 * the wanted length. If we don't know the length, report an error.
2687 if ((length
==(-1)) && (mt
->edescr
.negative
))
2688 exiterror( ERR_INCORRECT_CALL
, 0 ) ;
2691 * Then we have to determine if this actually is a whole number.
2692 * There are two things that might be wrong: a non-zero fractional
2693 * part (checked in the 'else' part below; or a insufficient
2694 * precition (handled in the if part below).
2696 if (mt
->edescr
.size
< mt
->edescr
.exp
)
2698 exiterror( ERR_INVALID_INTEGER
, 0 ) ;
2700 else if (mt
->edescr
.size
> mt
->edescr
.exp
)
2703 * Make sure that all digits in the fractional part is zero
2705 for (i
=MIN(mt
->edescr
.exp
,0); i
<mt
->edescr
.exp
; i
++)
2707 if (mt
->edescr
.num
[i
]!='0')
2709 exiterror( ERR_INVALID_INTEGER
, 0 ) ;
2715 * If the number is zero, a special case applies, the return value
2716 * is a nullstring. Same if length is zero. I am not sure if this
2717 * is needed, or if the rest of the algoritm is general enough to
2718 * handle these cases too.
2720 if ((length
==0) /* || ((mt->edescr.num[0]=='0') && (mt->edescr.size=1)) */)
2721 result
=nullstringptr() ;
2724 * Here comes the real work. To ease the implementation it is
2725 * devided into two parts based on whether or not length is
2728 else if (length
==(-1))
2731 * First, let's estimate the size of the output string that
2732 * we need. A crude (over)estimate is one char for every second
2733 * decimal digits. Also set length, just to chache the value.
2734 * (btw: isn't that MAX( ,0) unneeded? Since number don't have
2735 * a decimal part, and since it must have a integer part (else
2736 * it would be zero, and then trapped above.)
2738 assert(mt
->edescr
.exp
> 0) ;
2739 result
= Str_makeTSD( (length
=(MAX(mt
->edescr
.exp
,0))/2) + 1 ) ;
2740 res_ptr
= result
->value
;
2744 * Let's loop from the least significant part of edescr. For each
2745 * iteration we devide mt->edescr by 256, stopping when edescr is
2748 for (i
=length
; ; i
--)
2751 * Perform the integer divition, edescr gets the quotient,
2752 * while fdescr get the reminder. Afterwards, perform some
2753 * makeup on the numbers (that might not be needed?)
2755 /* may hang if acc==zero ? */
2756 string_div( TSD
, &mt
->edescr
, &byte
, &mt
->fdescr
, &mt
->edescr
, DIVTYPE_BOTH
) ;
2757 str_strip( &mt
->edescr
) ;
2758 str_strip( &mt
->fdescr
) ;
2761 * Now, fdescr has the reminder, stuff it into the result string
2762 * before it escapes :-) (don't we have to cast lvalue here?)
2763 * Afterwards, check to see if there are more digits to extract.
2765 result
->value
[i
] = (char) descr_to_int( &mt
->fdescr
) ;
2766 if ((mt
->edescr
.num
[0]=='0') && (mt
->edescr
.size
==1))
2771 * That's it, now we just have to align the answer and set the
2772 * correct length. Have to use memmove() since strings may
2775 memmove( result
->value
, &result
->value
[i
], length
+1-i
) ;
2776 result
->len
= length
+ 1 - i
;
2781 * We do have a specified length for the number. At least that
2782 * makes it easy to deside how large the result string should be.
2784 result
= Str_makeTSD( length
) ;
2785 res_ptr
= result
->value
;
2788 * In the loop, iterate once for each divition of 256, but stop
2789 * only when we have reached the start of the result string.
2790 * Below, edescr gets the quotient and fdescr gets the reminder.
2792 for (i
=length
-1; i
>=0; i
--)
2794 /* may hang if acc==zero ? */
2795 string_div( TSD
, &mt
->edescr
, &byte
, &mt
->fdescr
, &mt
->edescr
, DIVTYPE_BOTH
) ;
2796 str_strip( &mt
->edescr
) ;
2797 str_strip( &mt
->fdescr
) ;
2800 * If the reminder is negative (i.e. quotient is negative too)
2801 * then add 256 to the reminder, to bring it into the range of
2802 * an unsigned char. To compensate for that, subtract one from
2803 * the quotient. Store the reminder.
2805 if (mt
->fdescr
.negative
)
2807 /* the following two lines are not needed, but it does not
2808 work without them. */
2809 if ((mt
->edescr
.size
==1) && (mt
->edescr
.num
[0]=='0'))
2810 mt
->edescr
.exp
= 1 ;
2812 string_add( TSD
, &mt
->edescr
, &minus_one
, &mt
->edescr
) ;
2813 str_strip( &mt
->edescr
) ;
2814 string_add( TSD
, &mt
->fdescr
, &byte
, &mt
->fdescr
) ;
2816 result
->value
[i
] = (char) descr_to_int( &mt
->fdescr
) ;
2819 * That's it, store the length
2821 result
->len
= length
;
2825 * We're finished ... hope it works ...
2831 streng
*str_normalize( const tsd_t
*TSD
, const streng
*number
)
2836 if (getdescr( TSD
, number
, &mt
->fdescr
))
2837 exiterror( ERR_BAD_ARITHMETIC
, 0 ) ;
2839 return str_norm( TSD
, &mt
->fdescr
, NULL
) ;
2844 num_descr
*is_a_descr( const tsd_t
*TSD
, const streng
*number
)
2846 num_descr
*new=NULL
;
2851 if (getdescr( TSD
, number
, &mt
->fdescr
))
2854 new = MallocTSD( sizeof( num_descr
)) ;
2858 descr_copy( TSD
, &mt
->fdescr
, new ) ;
2863 int myiswnumber( const tsd_t
*TSD
, const streng
*number
)
2866 * Checks if number is a whole number according to NUMERIC DIGITS.
2867 * We DON'T check for NUMERIC FORM if the resulting string would have
2875 if (getdescr(TSD
, number
, &mt
->fdescr
))
2877 str_round(&mt
->fdescr
, TSD
->currlevel
->currnumsize
);
2879 if (i
<= 0) /* 0.?? */
2881 for (; i
< mt
->fdescr
.size
; i
++)
2883 if (mt
->fdescr
.num
[i
] != '0') /* decimal part not zero */
2890 /* Converts number to an integer. Sets *error to 1 on error (0 otherwise) */
2891 int streng_to_int( const tsd_t
*TSD
, const streng
*number
, int *error
)
2899 if (getdescr( TSD
, number
, &mt
->fdescr
))
2902 str_round( &mt
->fdescr
, TSD
->currlevel
->currnumsize
) ;
2903 if (mt
->fdescr
.exp
> mt
->fdescr
.size
) /* precision of less than one */
2906 i
= mt
->fdescr
.exp
;
2909 for (; i
<mt
->fdescr
.size
; i
++)
2911 if (mt
->fdescr
.num
[i
] != '0') /* decimal part not zero */
2914 if (mt
->fdescr
.exp
>9)
2915 goto errorout
; /* thus, a 32 bit integer should be sufficient */
2918 for (i
=0; i
<mt
->fdescr
.exp
; i
++)
2919 result
= result
* 10 + (mt
->fdescr
.num
[i
]-'0') ;
2921 if (mt
->fdescr
.negative
)