NumberStringMath2.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.oorexx.org/license.html */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /******************************************************************************/
39 /* REXX Kernel okmath2.c */
40 /* */
41 /* Arithmetic function for the NumberString Class */
42 /* Multiply/Divide/Power */
43 /* */
44 /******************************************************************************/
45 #include <ctype.h>
46 #include <stdlib.h>
47 #include <string.h>
48 
49 #include "RexxCore.h"
50 #include "NumberStringClass.hpp"
51 #include "ArrayClass.hpp"
52 #include "BufferClass.hpp"
53 #include "RexxActivity.hpp"
54 #include "NumberStringMath.hpp"
55 #include "ActivityManager.hpp"
56 #include "ProtectedObject.hpp"
57 
59  char *top, /* data pointer of "top" number */
60  size_t topLen, /* length of the top number */
61  char *AccumPtr, /* output accumulator location */
62  int MultChar) /* multiplier value */
63 /*********************************************************************/
64 /* Function: Multiply current digit through "top" number and add */
65 /* result to the accumulator. */
66 /*********************************************************************/
67 {
68  int carry, ResultChar;
69 
70  carry = 0; /* no carry at this point. */
71  top += (topLen - 1); /* move data point to end of data. */
72 
73  /* while there are digits left to */
74  /* multiply and there is room to put */
75  /* more digits. */
76  while (topLen-- )
77  {
78  /* Multiply char by top digit and add*/
79  /* the accumvalue for position and */
80  /* and carry. and adjust pointer to */
81  /* the next digit positions. */
82  ResultChar = carry + *AccumPtr + (MultChar * *top--);
83  if (ResultChar >= 10)
84  { /* Do we have carry to worry about? */
85  carry = ResultChar / 10; /* Yes, calculate the carry over. */
86  ResultChar -= carry * 10; /* adjust number down. */
87  }
88  else
89  {
90  carry = 0; /* no carry, */
91  }
92  *AccumPtr-- = ResultChar; /* Set result char to the accum pos */
93  /* and point accum to next position. */
94  }
95  if (carry)
96  { /* still room to put a digit */
97  *AccumPtr-- = (char)carry; /* yes, put carry into next pos. */
98  }
99  return ++AccumPtr; /* return pointer to start of Accum. */
100 }
101 
103 /*********************************************************************/
104 /* Function: Multiply two NumberString objects */
105 /*********************************************************************/
106 {
107  RexxNumberString *left, *right, *result, *LargeNum, *SmallNum;
108  char *ResultPtr, *AccumPtr, *Current, *OutPtr;
109  char MultChar;
110  size_t AccumLen;
111  size_t i;
112  size_t NumberDigits, TotalDigits, ExtraDigit;
113  char resultBufFast[FASTDIGITS]; /* fast allocation if default digits */
114 
115  NumberDigits = number_digits(); /* Get the current Numeric Digits */
116 
117  /* prepare both numbers */
118  left = this->checkNumber(NumberDigits);
119  right = other->checkNumber(NumberDigits);
120  /* either number 0 to begin with? */
121  if (left->sign == 0 || right->sign == 0)
122  {
123  return new_numberstring("0", 1); /* Yes, then result is Zero. */
124  }
125 
126  if (left->length > right->length)
127  { /* Determine the large number */
128  LargeNum = left; /* left is larger, set up large and */
129  SmallNum = right; /* small for right */
130  }
131  else
132  {
133  LargeNum = right; /* right is larger, set up large and */
134  SmallNum = left; /* small for left. */
135  }
136 
137  TotalDigits = ((NumberDigits+1) * 2) + 1;
138  /* working with large numbers? */
139  if (TotalDigits > FASTDIGITS)
140  {
141  /* get a work are for result digits. */
142  OutPtr = buffer_alloc(TotalDigits);
143  }
144  else
145  {
146  OutPtr = resultBufFast; /* use the local version */
147  }
148  memset(OutPtr,'\0',TotalDigits); /* Make sure work area is zero */
149 
150  AccumPtr = OutPtr; /* Set up our acummulator */
151  AccumLen = 0; /* no data at this time. */
152  /* Set up result Pointer. Point to */
153  /* the end of the data. */
154  ResultPtr = AccumPtr + TotalDigits - 1;
155  /* Set up current digit ptr. */
156  Current = SmallNum->number + SmallNum->length;
157 
158  /* do for all multiplier digits */
159  for (i = SmallNum->length ; i ; i-- )
160  {
161  Current--; /* shift add location by 1. */
162  MultChar = *Current; /* get new multiplier digit. */
163  if (MultChar)
164  { /* is this new digit a Zero? */
165  /* nope, go do multiplication of */
166  /* digit */
167  AccumPtr = addMultiplier(LargeNum->number, LargeNum->length, ResultPtr, MultChar);
168  }
169  /* If number is zero we don't need */
170  /* to do anything. */
171  ResultPtr--; /* Backup Result Ptr, for next digit */
172  } /* go do next digit. */
173  /* Get length of computed number. */
174  AccumLen = (++ResultPtr - AccumPtr) + SmallNum->length;
175 
176  /* AccumPtr now points to result, */
177  /* the len of result is in AccumLen */
178 
179  /* now get a real Object for dat */
180  if (AccumLen > NumberDigits)
181  { /* Is result len greater then Digits */
182  /* save amount over digits for exp */
183  ExtraDigit = AccumLen -(NumberDigits + 1);
184  AccumLen = NumberDigits + 1; /* we will only use Digits + 1 */
185  }
186  else
187  {
188  ExtraDigit = 0; /* Length OK, no adjusting Exp. */
189  }
190 
191  /* go get the new object. */
192  result = (RexxNumberString *)new_numberstring(NULL, AccumLen);
193  /* get the result exponent */
194  result->exp = LargeNum->exp + SmallNum->exp + ExtraDigit;
195  /* Compute the Sign */
196  result->sign = LargeNum->sign * SmallNum->sign;
197  result->length = AccumLen; /* Set length of result. */
198  /* Make sure result is in correct */
199  /* precision */
200  result->adjustPrecision(AccumPtr, NumberDigits);
201  return result; /* return computed value. */
202 } /* All done, */
203 
204 char *RexxNumberString::subtractDivisor(char *data1, size_t length1,
205  char *data2, size_t length2,
206  char *result, int Mult)
207 /*********************************************************************/
208 /* Function: Subtraction routine for division */
209 /*********************************************************************/
210 {
211  char *OutPtr;
212  int carry, DivChar;
213  size_t extra;
214  /* This rountine actually does the divide of the Best Guess */
215  /* Mult. This Best guess is a guess at how many times the */
216  /* dividend will go into the divisor, since it is only a */
217  /* guess we make sure we guess to the low side, if low we */
218  /* always adjust our guess and recompute. */
219  /* We multiply the Dividend(Data2) by mult and then subtract*/
220  /* the result from the Divisor (Data1) and this result is */
221  /* put into RESULT. Since Mult is guaranteed to be correct*/
222  /* or low, the result is guaranteed to never be negative. */
223 
224  /* xxMxxx <- M signifies this Mult */
225  /* ______________ */
226  /* dividend ) divisor */
227  /* -iiiiiiiii <- result of M x Divisor */
228  /* =========== */
229  /* rrrrrrrrr <- result returned */
230 
231 
232  data1 += (length1 -1); /* point to end of data1 */
233  data2 += (length2 -1); /* point to end of data2 */
234 
235  OutPtr = result + 1; /* setup output pointer */
236  carry = 0; /* no carry at this point. */
237  extra = length1 - length2; /* get extra byte count. */
238 
239  while (length2--)
240  { /* do all digits in second number */
241  /* compute this div value, and bump */
242  /* data pointer to the next digit. */
243  DivChar = carry + *data1-- - (*data2-- * Mult);
244  if (DivChar < 0)
245  { /* is this div value negative? */
246  DivChar += 100; /* make it positive, by adding 100 */
247  carry = (DivChar/10) -10; /* calculate borrow out. */
248  DivChar %= 10; /* compute real result remainder */
249  }
250  else /* div value is not negative. */
251  {
252  carry = 0; /* clear out carry value. */
253  }
254  *--OutPtr = (char)DivChar; /* set this digit in output */
255  } /* go back and do next divide. */
256 
257  if (extra)
258  { /* is ther more to process? */
259  if (!carry)
260  { /* is there a carry left over? */
261  while (extra--) /* no, just copy each remaining */
262  {
263  *--OutPtr = (char)*data1--; /* digit from data1. */
264  }
265  }
266  else
267  {
268  while (extra--)
269  { /* carry left over, do for all extra */
270  DivChar = carry + *data1--; /* add carry to digit. */
271  if (DivChar < 0)
272  { /* is result negative? */
273  DivChar += 10; /* add 10(borrow) to digit value */
274  carry = -1; /* have another carry. */
275  *--OutPtr = (char)DivChar; /* put digit into result */
276  }
277  else
278  {
279  *--OutPtr = (char)DivChar; /* finished w/ carry place in result */
280  while (extra--) /* now just copy rest of digits */
281  {
282  *--OutPtr = *data1--; /* and adjust for next digit. */
283  }
284  break; /* all done, break out of loop */
285  }
286  }
287  }
288  }
289  return OutPtr; /* return pointer to start of result */
290 }
291 
292 
294 /*********************************************************************/
295 /* Function: Divide two numbers */
296 /*********************************************************************/
297 {
298  RexxNumberString *left, *right;
299  RexxNumberStringBase *Accum; /* dummy accumulator object */
300  RexxNumberStringBase *SaveLeft; /* dummy operator object */
301  RexxNumberStringBase *SaveRight; /* dummy operator object */
302  /* buffers for dummy arguments */
303  char AccumBuffer[sizeof(RexxNumberStringBase)];
304  char SaveLeftBuffer[sizeof(RexxNumberStringBase)];
305  char SaveRightBuffer[sizeof(RexxNumberStringBase)];
306  RexxNumberString *result;
307  char *Num1, *Num2;
308  char *resultPtr, *Output, *rightPtr, *leftPtr, *SaveLeftPtr, *SaveRightPtr;
309  wholenumber_t multiplier, rc;
310  wholenumber_t DivChar, thisDigit;
311  wholenumber_t CalcExp;
312 
313  size_t NumberDigits, totalDigits, resultDigits;
314  size_t adjustNum1;
315  char leftBufFast[FASTDIGITS]; /* fast allocation if default */
316  char rightBufFast[FASTDIGITS]; /* fast allocation if default */
317  char outBufFast[FASTDIGITS]; /* fast allocation if default */
318  size_t rightPadding; /* amount right side is padded by */
319 
320  SaveLeftPtr = NULL;
321 
322  /* NOTE: this routine if very similiar to the PowerDivide */
323  /* routine, these we kept as seperate routines since there*/
324  /* are enough subtile differences between the objectPointererations */
325  /* that combining them would make an already complex */
326  /* routine even more so. When fixing/updating/adding to */
327  /* this routin also check PowerDivide for similiar updates*/
328 
329  if (!other->sign)
330  { /* is the right number zero? */
331  /* yes, divide by Zero. */
333  }
334  else if (!this->sign)
335  { /* is left number Zero? */
336  /* yes, just return a zero. */
337  return(RexxNumberString *)IntegerZero;
338  }
339  /* set up address of temporaries */
340  Accum = (RexxNumberStringBase *)AccumBuffer;
341  SaveLeft = (RexxNumberStringBase *)SaveLeftBuffer;
342  SaveRight = (RexxNumberStringBase *)SaveRightBuffer;
343  NumberDigits = number_digits(); /* get current digits setting. */
344  /* make sure we've got good copy of */
345  /* our working numbers */
346  left = this->checkNumber(NumberDigits);
347  right = other->checkNumber(NumberDigits);
348  CalcExp = left->exp - right->exp; /* compute the new exponents */
349  /* calculate expected resultant exp */
350  CalcExp += (wholenumber_t)left->length - (wholenumber_t)right->length;
351  /* is exp < 0 and doing // or % */
352  if (CalcExp < 0 && DivOP != OT_DIVIDE)
353  {
354  if (DivOP == OT_INT_DIVIDE)
355  { /* Are we doing % (integer Divide)? */
356  /* yes, result is zero. */
357  return(RexxNumberString *)IntegerZero;
358  }
359  else
360  {
361  /* We are doing //, return left(this)*/
362  result = left->prepareOperatorNumber(NumberDigits + 1, NumberDigits, NOROUND);
363  result->setupNumber();
364  return result;
365  }
366  }
367 
368  totalDigits = ((NumberDigits + 1) * 2) + 1;
369  if (totalDigits > FASTDIGITS)
370  { /* working with large numbers? */
371  /* No fast path here, do Division */
372  /* get buffer for left digit data. */
373  leftPtr = buffer_alloc(totalDigits);
374  /* and right digit data */
375  rightPtr = buffer_alloc(totalDigits);
376  /* get buffer for result digit data. */
377  Output = buffer_alloc(totalDigits);
378  }
379  else
380  {
381  leftPtr = leftBufFast; /* use non-allocated version for the */
382  rightPtr = rightBufFast;
383  Output = outBufFast;
384  }
385  /* now copy the data itself into */
386  /* the temp data buffers. */
387  memcpy(leftPtr,left->number, left->length);
388  /* pad the output area with zeros. */
389  memset(leftPtr + left->length, '\0', totalDigits - left->length);
390  memcpy(rightPtr, right->number, right->length);
391  /* pad the output area with zeros. */
392  memset(rightPtr + right->length, '\0', totalDigits - right->length);
393  resultPtr = Output; /* Set up result, point to end of */
394  /* make copies of right number info */
395  memcpy((void *)SaveRight, (void *)right, sizeof(RexxNumberStringBase));
396  /* make copies of left number info */
397  memcpy((void *)SaveLeft, (void *)left, sizeof(RexxNumberStringBase));
398  if (DivOP == OT_REMAINDER)
399  { /* Are we doing remainder divide? */
400  SaveLeftPtr = leftPtr; /* Save initial pointers to left */
401  SaveRightPtr = rightPtr; /* and right numbers. */
402  SaveRight->sign = 1; /* force dividend sign positive. */
403  }
404  /* compute sign of result. */
405  Accum->sign = left->sign * SaveRight->sign;
406 
407  /* is right numebr longer than left? */
408  if (SaveRight->length > SaveLeft->length)
409  {
410  SaveLeft->length = SaveRight->length;/* set both numbers to same length */
411  rightPadding = 0; /* no padding needed for right number*/
412  }
413  else
414  { /* Left number is longer. */
415  /* no padding needed for right number*/
416  rightPadding = SaveLeft->length - SaveRight->length;
417  SaveRight->length = SaveLeft->length;/* set both numbers to same length */
418  }
419 
420  /* Set the new exponents of two */
421  SaveLeft->exp = NumberDigits * 2 - SaveLeft->length + 1;
422  SaveRight->exp = rightPadding; /* work numbers. */
423  adjustNum1 = 0; /* Set to 0 to start with. */
424  Num1 = leftPtr; /* Num1 is ldivisor digit pointer */
425  Num2 = rightPtr; /* Num2 is dividend digit pointer */
426 
427  /* When generate a best guess digits for result we will look*/
428  /* use the 1st 2 digits of the dividend (if there are 2) */
429  /* we then add 1 to this DivChar to ensure than when we gues*/
430  /* we either guess correctly of under guess. */
431  /* _______________ */
432  /* aabbbbbb ) xxyyyyyyyy */
433  /* */
434  /* DivChar = aa + 1 */
435 
436  DivChar = *Num2 * 10; /* Divide char is the 1st 2 digits + 1 */
437  if (SaveRight->length > 1) /* more than 1 digit in Accum? */
438  {
439  DivChar += *(Num2 + 1); /* yes, get second digit for Div */
440  }
441  DivChar++; /* add 1 to Div number */
442  resultDigits = 0; /* initializes digit values to zero. */
443  thisDigit = 0;
444 
445  /* We are now to enter 2 do forever loops, inside the loops */
446  /* we test for ending conditions. and will exit the loops */
447  /* when needed. This inner loop may need to break out of */
448  /* both loops, if our divisor is reduced to zero(all finish*/
449  /* if this happens to do the no-no nad use a GOTO. */
450  /* The outer loop is used to obtain all digits for the resul*/
451  /* We continue in this loop while the divisor has NOT been */
452  /* reduced to zero and we have not reach the maximum number*/
453  /* of digits to be in the result (NumDigits + 1), we add */
454  /* one to NumDigits so we can round if necessary. */
455  /* The inner loop conputs each digits of the result and */
456  /* breaks to the outer loop when the next digit of result */
457  /* is found. */
458  /* We compute a digit of result by continually taking best */
459  /* guesses at how many times the dividend can go into the */
460  /* divisor. Once The divisor becomes less than the dividend*/
461  /* we found this digit and we exit the inner loop. If the */
462  /* divisor = dividend then we know dividend will go into */
463  /* 1 more than last guess, so bump up the last guess and */
464  /* exit both loops (ALL DONE !!), if neither of the above */
465  /* conditions are met our last guess was low, compute a new*/
466  /* guess using result of last one, and go though inner loop*/
467  /* again. */
468  for (; ; )
469  { /* do forever (outer loop) */
470  for (; ; )
471  { /* do forever (inner loop) */
472  /* are two numbers equal in length? */
473  if (SaveLeft->length == SaveRight->length)
474  {
475  /* yes, then compare two numbers */
476  rc = memcmp(Num1, Num2, SaveLeft->length);
477  if (rc < 0) /* is Num1(left) smaller? */
478  {
479  break; /* yes, break out of inner loop. */
480  }
481 
482  /* are the two numebrs equal and not */
483  /* doing // */
484  else if (rc == 0 && DivOP != OT_REMAINDER)
485  {
486  /* yes, done with Division, cleanup */
487  *resultPtr++ = (char)(thisDigit + 1);
488  resultDigits++; /* one more digit in result */
489  goto PowerDivideDone; /* break out of both loops. */
490  }
491  else /* Either rc >0 or doing // */
492  {
493  multiplier = *Num1; /* Lengths of nums are equal we only */
494  /* need to use 1 digits from divisor */
495  /* to this next guess. */
496  }
497  }
498  /* is left longer than Accum? */
499  else if (SaveLeft->length > SaveRight->length)
500  {
501  /* calculate multiplier, next two */
502  /*digits */
503  multiplier = *Num1 * 10 + *(Num1 + 1);
504  }
505  else
506  {
507  break; /* Divisor is smaller than dividend, */
508  }
509  /* we found this digit of result, go */
510  /* to outer loop and finish up */
511  /* processing for this digit. */
512  /* compute Multiplier for actual */
513  /*divide */
514  multiplier = multiplier * 10 / DivChar;
515  /* that is how many times will digit */
516  /* of dividend go into divisor, using*/
517  /* the 1st 2 digits of each number */
518  /* compute our Best Guess for this */
519  /* digit */
520  if (multiplier == 0) /* did it compute to 0? */
521  {
522  multiplier = 1; /* yes, can't be zero make it one. */
523  }
524  /* we know dividend goes into */
525  /* divisor at least one more time. */
526  thisDigit += multiplier; /* add multiplier to this digit. */
527 
528 
529  /* Go and actualy see if we guessed */
530  /* correctly, Divide digit through */
531  Num1 = subtractDivisor(Num1, SaveLeft->length, Num2, SaveRight->length, Num1 + SaveLeft->length - 1, (int)multiplier);
532  /* while we have leading zeros */
533  while (*Num1 == 0 && SaveLeft->length > 1)
534  {
535  Num1++; /* step to the next digit */
536  SaveLeft->length--; /* and reduce the length also */
537  }
538  /* end of inner loop, go back and */
539  /* guess again !! */
540  }
541  if (resultDigits || thisDigit)
542  { /* Have a digit for result? */
543  *resultPtr++ = (char) thisDigit; /* yes, place digit in result. */
544  thisDigit = 0; /* reset digit value to zero; */
545  resultDigits++; /* one more digit in result; */
546 
547  /* has dividend reduced to zero, */
548  /* run out of room for additional? */
549  if (*Num1 == '\0' || resultDigits > NumberDigits)
550  {
551  break; /* yes, were done, exit outer loop */
552  }
553 
554  }
555 
556  if (DivOP != OT_DIVIDE)
557  { /* Are we doing // or % */
558  if (CalcExp <= 0) /* have we finished integer part? */
559  {
560  break; /* yes, all done here, break out */
561  }
562  }
563  /* Was number reduced to zero? */
564  if (SaveLeft->length == 1 && *Num1 == '\0')
565  {
566  break; /* yes, all done exit outer loop */
567  }
568 
569 
570  /* we're not done dividing yet, we */
571  /* need to adjust expected exponent */
572  /* by one to the left */
573  CalcExp--; /* result exponent is one less. */
574  if (rightPadding > 0)
575  { /* are we still "padding" number for */
576  /* right number? */
577  SaveRight->length--; /* yes, length of right is one less. */
578  rightPadding--; /* now padding one less digit. */
579  }
580  else
581  {
582  SaveLeft->length++; /* length of left is now one more. */
583  }
584  } /* end of outer loop */
585 
586  PowerDivideDone: /* done doing actual divide now do */
587  ; /* the cleanup stuff. */
588 
589  if ((DivOP != OT_DIVIDE) && /* Is this a // or % operation, and */
590  (( CalcExp >= 0 && /* and is the result bad? */
591  ( resultDigits + CalcExp) > NumberDigits) ||
592  (CalcExp < 0 && (size_t)Numerics::abs(CalcExp) > resultDigits)))
593  {
594  /* yes, report the error and get out.*/
595  if (DivOP == OT_REMAINDER) /* remainder operation? */
596  {
598  }
599  else
600  {
602  }
603  }
604  if (DivOP == OT_REMAINDER)
605  { /* Are we doing // */
606  if (resultDigits)
607  { /* any numbers in result? */
608  if (*Num1)
609  { /* yes, but was it Zero? */
610  /* nope, we got a real remainder */
611  resultPtr = Num1; /* set result to point to remainder */
612  /* we need to compute the exponent */
613  /* of our result. */
614  SaveLeftPtr += left->length; /* point to end of input. */
615  /* point to existing location. */
616  SaveRightPtr = resultPtr + SaveLeft->length + adjustNum1;
617  /* Adjust for added Zeros. */
618  Accum->exp = left->exp - (SaveRightPtr - SaveLeftPtr);
619  Accum->length = SaveLeft->length; /* length of result is that of the */
620  /* remaining divisor digits. */
621  }
622  else
623  {
624  /* result is 0, just return it. */
625  return(RexxNumberString *)IntegerZero;
626  }
627  }
628  /* no digits in result, remainder is */
629  /* the left number (this) */
630  else
631  {
632  /* return a copy of Div(left) number */
633  result = this->clone();
634  result->setupNumber();
635  return result;
636  }
637  }
638  else
639  { /* real division... compute answer. */
640  if (resultDigits)
641  { /* any number in result? */
642  /* Set resultPtr to start of our */
643  /* buffer */
644  resultPtr = Output;
645  Accum->length = resultDigits; /* length is digits in result. */
646  Accum->exp = CalcExp; /* set exp to that calculated above. */
647  if (Accum->length > NumberDigits)
648  {/* is result too big? */
649  /* Yes, we need to adjust result */
650  /* increase exponent by amount over. */
651  Accum->exp += (Accum->length - NumberDigits);
652  Accum->length = NumberDigits; /* Length is same as Digits */
653  Accum->mathRound(resultPtr); /* round result if necessary. */
654  }
655  /* We now remove any trailing zeros */
656  /* point to last digit in result */
657  Num1 = resultPtr + Accum->length - 1;
658  while (!*Num1 && Accum->length)
659  { /* While there are trailing zeros */
660  Num1--; /* point to next character. */
661  Accum->length--; /* Result is one digit less. */
662  Accum->exp++; /* Adjust expont up one */
663  }
664  }
665  else
666  {
667  /* no digits in result answer is */
668  /* zero. */
669  return(RexxNumberString *)IntegerZero;
670  }
671  } /* End final processing */
672  result = new (Accum->length) RexxNumberString (Accum->length);
673 
674  result->length = Accum->length; /* set length of result */
675  result->exp = Accum->exp; /* set exponent of result. */
676  result->sign = Accum->sign; /* set sign of result. */
677  /* move result data to result area */
678  result->adjustPrecision(resultPtr, NumberDigits);
679  return result; /* all done, return to caller. */
680 }
681 
683 /*********************************************************************/
684 /* Function: Perform the Arithmetic power operation */
685 /*********************************************************************/
686 {
687  wholenumber_t powerValue;
688  wholenumber_t extra, OldNorm;
689  size_t NumberDigits;
690  char *Accum, *AccumPtr, *OutPtr, *TempPtr;
691  bool NegativePower;
692  RexxNumberStringBase *AccumObj;
693  RexxNumberString *left;
694  RexxNumberString *result;
695  size_t NumBits;
696  size_t AccumLen;
697 
698  NegativePower = false; /* Initialize the flags. */
699  requiredArgument(PowerObj, OREF_positional, ARG_ONE); /* must have one argument */
700  /* get the whole number value */
701  if (!PowerObj->numberValue(powerValue, number_digits()))
702  {
703  ProtectedObject result;
704  RexxObject *self = this;
705  RexxObject *args[1];
706  args[0] = self; // positional argument
707  bool alternativeResult = PowerObj->messageSend(OREF_POWER_RIGHT, args, 1, 0, result, false);
708  if (alternativeResult && (RexxObject *)result != OREF_NULL) return (RexxNumberString *)(RexxObject *)result;
710  }
711 
712  if (powerValue < 0)
713  { /* is the power negative? */
714  NegativePower = true; /* yes, mark for later. */
715  powerValue = -powerValue; /* make power positive, we first do */
716  /* power as if positive then */
717  /* invert value (1/x) */
718  }
719  NumberDigits = number_digits(); /* get the current Digits Setting. */
720  /* make a copy of self, since we may */
721  /* need to adjust some of its data. */
722  left = this->prepareOperatorNumber(NumberDigits+1, NumberDigits, NOROUND);
723 
724  if (left->sign == 0)
725  { /* Is the base number Zero? */
726  if (NegativePower) /* was power negative? */
727  {
728  /* this is a no no, report error. */
730  }
731  else if (powerValue == 0) /* Is power value zero? */
732  {
733  /* yes, return value of one */
734  return(RexxNumberString *)IntegerOne;
735  }
736  else /* otherwise power was positive */
737  {
738  /* return value of zero */
739  return(RexxNumberString *)IntegerZero;
740  }
741 
742  } /* Will the result exponent overflow?*/
743  if ((highBits(Numerics::abs(left->exp + left->length - 1)) +
744  highBits(Numerics::abs(powerValue)) + 1) > LONGBITS )
745  {
746  /* yes, report error and return. */
747  reportException(Error_Overflow_overflow, this, OREF_POWER, PowerObj);
748  }
749  /* Will the result overflow ? */
750  if (Numerics::abs((wholenumber_t)(left->exp + left->length - 1)) * powerValue > Numerics::MAX_EXPONENT)
751  {
752  /* yes, report error and return. */
753  reportException(Error_Overflow_overflow, this, OREF_POWER, PowerObj);
754  }
755 
756  if (powerValue != 0)
757  { /* a non-zero power value? */
758  /* yes, do the power operation. */
759  /* get storage for Accumulator data. */
761  memcpy((void *)AccumObj, (void *)left, sizeof(RexxNumberStringBase));
762  /* initialize the Accumulator object.*/
763  /* this has all data of NumberString */
764  /* except the digits data */
765 
766  /* Find out how many digits are in */
767  /* power value, needed for actual */
768  /* precision value to be used in */
769  /* the computation. */
770  for (extra=0, OldNorm = powerValue; OldNorm ;extra++ )
771  {
772  OldNorm /= 10; /* Divide value by ten, keeping int */
773  }
774  NumberDigits += (extra + 1); /* adjust digits setting to reflect */
775 
776  /* size of buffers, for */
777  /*multiplication */
778  AccumLen = (2 * (NumberDigits+1)) + 1;
779  /* get storage for Output data */
780  OutPtr = buffer_alloc(AccumLen);
781  /* get storage for Accumulator Data */
782  Accum = buffer_alloc(AccumLen);
783  AccumPtr = Accum; /* Accum will point to start of */
784  /* storage block that AccumPtr is in.*/
785 
786  /* Initialize Accumulator digit data */
787  /* start with initial data. */
788  memcpy(AccumPtr, left->number, left->length);
789  /* The power operation is defined */
790  /* to use bitwise reduction */
791 
792  NumBits = LONGBITS; /* Get total number of bits in long */
793 
794  /* Find first non-zero left most bit */
795  while (!((size_t)powerValue & HIBIT))
796  {
797  powerValue <<= 1; /* bit is zero shift bits 1 to left */
798  NumBits--; /* one less bit. */
799  } /* endwhile */
800 
801  /* turn off this 1st 1-bit, already */
802  /* taken care of. Skip 1st Multiply */
803  powerValue = (wholenumber_t) ((size_t)powerValue & LOWBITS);
804 
805  while (NumBits--)
806  { /* while 1-bits remain in power. */
807  if ((size_t) powerValue & HIBIT)
808  { /* is left most bit a 1? */
809  /* yes, we need to multiply number by*/
810  /* Acummulator. */
811  /* go do multiply. AccumPtr will get*/
812  /* assigned result of multiply */
813  AccumPtr = multiplyPower(AccumPtr, AccumObj, left->number, (RexxNumberStringBase *) left, OutPtr, AccumLen, NumberDigits);
814  /* We now call AdjustNumber to make */
815  /* sure we stay within the required */
816  /* precision and move the Accum */
817  /* data back to Accum. */
818  AccumPtr = AccumObj->adjustNumber(AccumPtr, Accum, AccumLen, NumberDigits);
819  }
820  if (NumBits)
821  { /* any 1-bits left in power? */
822  /* yes, we need to Square the Accum */
823  /* go do multiply. AccumPtr will get*/
824  /* assigned result of squaring */
825  AccumPtr = multiplyPower(AccumPtr, AccumObj, AccumPtr, AccumObj, OutPtr, AccumLen, NumberDigits);
826  /* We now call AdjustNumber to make */
827  /* sure we stay within the required */
828  /* precision and move the Accum */
829  /* data back to Accum. */
830  AccumPtr = AccumObj->adjustNumber(AccumPtr, Accum, AccumLen, NumberDigits);
831  }
832  powerValue <<= 1; /* shift power bits one to the left */
833  } /* Finished with Power 1st step. */
834 
835  if (NegativePower)
836  { /* is this a negative power operation*/
837  /* yes, so we need to invert value. */
838  AccumPtr = dividePower(AccumPtr, AccumObj, Accum, NumberDigits);
839  }
840 
841  NumberDigits -= (extra + 1); /* reset digits setting to original; */
842  /* Remove all leading zeros. */
843  AccumPtr = AccumObj->stripLeadingZeros(AccumPtr);
844 
845  /* Is result bigger than digits? */
846  if (AccumObj->length > NumberDigits)
847  {
848  /* Yes, we need to adjust result */
849  /* increase exponent by amount over. */
850  AccumObj->exp += (AccumObj->length - NumberDigits);
851  AccumObj->length = NumberDigits; /* Length is same as Digits */
852  AccumObj->mathRound(AccumPtr); /* round result if necessary. */
853  }
854  /* We now remove any trailing blanks */
855  /* point to last digit in result */
856  TempPtr = AccumPtr + AccumObj->length -1;
857  /* While there are trailing zeros */
858  while (!*TempPtr && AccumObj->length)
859  {
860  TempPtr--; /* point to next character. */
861  AccumObj->length--; /* Result is one digit less. */
862  AccumObj->exp++; /* Adjust expont up one */
863  }
864 
865  /* get new numberString Object for */
866  /* result length. No initial Data */
867  result = new (AccumObj->length) RexxNumberString (AccumObj->length);
868 
869  result->sign = AccumObj->sign; /* fill in the data of result from */
870  result->exp = AccumObj->exp; /* AccumObj. */
871  result->length = AccumObj->length;
872  /* copy digit data from AccumPtr. */
873  memcpy(result->number, AccumPtr, result->length);
874  }
875  else
876  { /* Power value is zero. */
877  /* result is 1. */
878  result = (RexxNumberString *)IntegerOne;
879  }
880  return result; /* return our result object. */
881 }
882 
884  char *rightPtr, RexxNumberStringBase *right,
885  char *OutPtr, size_t OutLen, size_t NumberDigits)
886 /*********************************************************************/
887 /* Function: Multiply numbers for the power operation */
888 /*********************************************************************/
889 {
890  char *current, *resultPtr;
891  char *AccumPtr = NULL;
892  char MultChar;
893  size_t AccumLen;
894  size_t i;
895  size_t ExtraDigit;
896 
897 
898  memset(OutPtr, '\0', OutLen); /* make output area is all zeros. */
899 
900  AccumLen = 0; /* no data at this time. */
901  resultPtr = OutPtr + OutLen - 1; /* Set up result, point to end of */
902  /* data. */
903  /* Set up digit ptr. small num */
904  current = rightPtr + right->length; /* get last digit of number. */
905 
906  for (i = right->length ; i ; i-- )
907  { /* do for all multiplier digits */
908  current--; /* shift add location by 1. */
909  MultChar = *current; /* get new multiplier digit. */
910  if (MultChar) /* is this new digit a Zero? */
911  {
912  /* nope, do multiplication of this */
913  /* digit */
914  AccumPtr = addMultiplier(leftPtr, left->length, resultPtr, MultChar);
915  }
916  resultPtr--; /* Backup Result Ptr, for next digit */
917  } /* go do next digit. */
918  /* Get length of computed number. */
919  AccumLen = (size_t)(++resultPtr - AccumPtr) + right->length;
920 
921  /* AccumPtr now points to result, and*/
922  /* the len of result is in AccumLen */
923 
924  /* We will now get a real Object */
925  if (AccumLen > NumberDigits)
926  { /* Is result len greater then Digits */
927  ExtraDigit = AccumLen - NumberDigits;/* Yes, save amount over for exp */
928  }
929  else
930  {
931  ExtraDigit = 0; /*Length OK, no adjusting Exp. */
932  }
933 
934  /* compute the resulting Exponent */
935  left->exp += (right->exp + ExtraDigit);
936  left->sign *= right->sign; /* Compute the Sign */
937  left->length = AccumLen; /* Set length of result. */
938 
939 
940  return AccumPtr; /* return Pointer to result digits. */
941 } /* All done, */
942 
943 char *RexxNumberString::dividePower(char *AccumPtr, RexxNumberStringBase *Accum, char *Output, size_t NumberDigits)
944 /*********************************************************************/
945 /* Function: Invert number from the power operation */
946 /*********************************************************************/
947 {
948  RexxNumberStringBase *left;
949  char leftBuffer[sizeof(RexxNumberStringBase)];
950  char *Num1, *Num2;
951  char *resultPtr, *leftPtr, *result;
952  int multiplier, rc;
953  int DivChar, thisDigit;
954  wholenumber_t CalcExp;
955  size_t resultDigits;
956  size_t totalDigits;
957 
958  /* NOTE: this routine if very similiar to the Division */
959  /* routine, these we kept as seperate routines since there*/
960  /* are enough subtile differences between the operations */
961  /* that combining them would make an already complex */
962  /* routine even more so. When fixing/updating/adding to */
963  /* this routin also check Division for similiar updates*/
964 
965  totalDigits = ((NumberDigits + 1) * 2) + 1;
966  /* get buffer for left digit data. */
967  leftPtr = buffer_alloc(totalDigits);
968  /* get buffer for result digit data. */
969  result = buffer_alloc(totalDigits);
970  resultPtr = result; /* Set up the result, point to end of*/
971  /* data. */
972  /* address the static part */
973  left = (RexxNumberStringBase *)leftBuffer;
974 
975  /* length of left starts same as */
976  /* Accum */
977  left->length = Accum->length;
978  left->exp = 0; /* no exponent to start with. */
979  *leftPtr = 1; /* place the digit 1 into left. */
980  /* fill the rest of data with Zero */
981  memset(leftPtr + 1, '\0', totalDigits - 1);
982  /* calculate expected resultant exp */
983  CalcExp = -Accum->exp - (wholenumber_t)Accum->length + 1;
984 
985  Num1 = leftPtr; /* Num1 will be left digit pointer. */
986  Num2 = AccumPtr; /* Num2 is our input digit pointer */
987 
988  /* When generate a best guess digits for result we will look*/
989  /* use the 1st 2 digits of the dividend (if there are 2) */
990  /* we then add 1 to this DivChar to ensure than when we gues*/
991  /* we either guess correctly of under guess. */
992  /* _______________ */
993  /* aabbbbbb ) xxyyyyyyyy */
994  /* */
995  /* DivChar = aa + 1 */
996 
997  DivChar = *Num2 * 10; /* Divide char is 1st 2 digits + 1 */
998  if (Accum->length > 1) /* more than 1 digit in Accum? */
999  DivChar += *(Num2 + 1); /* yes, get second digit for Div */
1000  DivChar++; /* add 1 to Div number */
1001 
1002  resultDigits = 0; /* initializes digit values to zero. */
1003  thisDigit = 0;
1004 
1005  /* We are now to enter 2 do forever loops, inside the loops */
1006  /* we test for ending conditions. and will exit the loops */
1007  /* when needed. This inner loop may need to break out of */
1008  /* both loops, if our divisor is reduced to zero(all finish*/
1009  /* if this happens to do the no-no nad use a GOTO. */
1010  /* The outer loop is used to obtain all digits for the resul*/
1011  /* We continue in this loop while the divisor has NOT been */
1012  /* reduced to zero and we have not reach the maximum number*/
1013  /* of digits to be in the result (NumDigits + 1), we add */
1014  /* one to NumDigits so we can round if necessary. */
1015  /* The inner loop conputs each digits of the result and */
1016  /* breaks to the outer loop when the next digit of result */
1017  /* is found. */
1018  /* We compute a digit of result by continually taking best */
1019  /* guesses at how many times the dividend can go into the */
1020  /* divisor. Once The divisor becomes less than the dividend*/
1021  /* we found this digit and we exit the inner loop. If the */
1022  /* divisor = dividend then we know dividend will go into */
1023  /* 1 more than last guess, so bump up the last guess and */
1024  /* exit both loops (ALL DONE !!), if neither of the above */
1025  /* conditions are met our last guess was low, compute a new*/
1026  /* guess using result of last one, and go though inner loop*/
1027  /* again. */
1028  for (; ; )
1029  { /* do forever (outer loop) */
1030  for (; ; )
1031  { /* do forever (inner loop) */
1032  /* are two numbers equal in length? */
1033  if (left->length == Accum->length)
1034  {
1035  /* yes, then compare the two numbers */
1036  rc = memcmp(Num1, Num2, left->length);
1037  if (rc < 0) /* is Num1(left) smaller? */
1038  {
1039  break; /* yes, break out of inner loop. */
1040  }
1041 
1042  else if (rc == 0)
1043  { /* are the two numebrs equal */
1044  /* yes, done with Division, cleanup */
1045  *resultPtr++ = (char)(thisDigit + 1);
1046  resultDigits++; /* one more digit in result */
1047  goto PowerDivideDone; /* break out of both loops. */
1048  }
1049  else
1050  {
1051  multiplier = *Num1; /* Num2(Accum) is smaller, */
1052  }
1053  }
1054  /* is left longer than Accum? */
1055  else if (left->length > Accum->length)
1056  {
1057  /* calculate multiplier, next two */
1058  /*digits */
1059  multiplier = *Num1 * 10 + *(Num1 + 1);
1060  }
1061  else
1062  {
1063  break; /* left is smaller, break inner loop */
1064  }
1065 
1066  /* compute Multiplier for divide */
1067  multiplier = multiplier * 10 / DivChar;
1068  if (multiplier == 0) /* did it compute to 0? */
1069  {
1070  multiplier = 1; /* yes, can't be zero make it one. */
1071  }
1072 
1073  thisDigit += multiplier; /* add multiplier to this digit. */
1074  /* now subtract */
1075  Num1 = subtractDivisor(Num1, left->length, Num2, Accum->length, Num1 + left->length - 1, multiplier);
1076  /* Strip off all leading zeros */
1077  Num1 = left->stripLeadingZeros(Num1);
1078  } /* end of inner loop */
1079 
1080  if (resultDigits || thisDigit)
1081  { /* Have a digit for result? */
1082  *resultPtr++ = (char) thisDigit; /* yes, place digit in result. */
1083  thisDigit = 0; /* reset digit value to zero; */
1084  resultDigits++; /* one more digit in result; */
1085 
1086  /* is there been reduced to zero */
1087  if (*Num1 == '\0' || resultDigits > NumberDigits)
1088  {
1089  break; /* yes, were done, exit outer loop */
1090  }
1091 
1092  }
1093  /* Was number reduced to zero? */
1094  if (left->length == 1 && *Num1 == '\0')
1095  {
1096  break; /* yes, all done exit outer loop */
1097  }
1098 
1099  CalcExp--; /* result exponent is one less. */
1100  left->length++; /* length is one more. */
1101 
1102  /* reset the number ptr to beginning */
1103  /* of the buffer. */
1104  Num1 = (char *)memmove(leftPtr, Num1, left->length);
1105  /* make sure traling end of buffer */
1106  /* is reset to 0's. */
1107  memset(Num1 + left->length, '\0', totalDigits - left->length);
1108  } /* end of outer loop */
1109 
1110  PowerDivideDone: /*All done doing divide now do */
1111  ; /* the cleanup stuff. */
1112 
1113  Accum->length = resultDigits; /* set length of result */
1114  Accum->exp = CalcExp; /* set exponent of result. */
1115  memcpy(Output, result, resultDigits); /* move result data to result area */
1116  return Output; /* all done, return to caller. */
1117 }
void reportException(wholenumber_t error)
RexxNumberString * new_numberstring(const char *s, stringsize_t l)
#define LONGBITS
#define FASTDIGITS
#define LOWBITS
#define OT_REMAINDER
#define OT_INT_DIVIDE
#define OT_DIVIDE
#define buffer_alloc(s)
#define NOROUND
#define HIBIT
size_t number_digits()
Definition: Numerics.hpp:155
#define OREF_NULL
Definition: RexxCore.h:60
#define IntegerOne
Definition: RexxCore.h:190
const int ARG_ONE
Definition: RexxCore.h:80
#define IntegerZero
Definition: RexxCore.h:189
void requiredArgument(RexxObject *object, RexxString *kind, size_t position)
Definition: RexxCore.h:291
#define Error_Overflow_overflow
#define Error_Overflow_power
#define Error_Invalid_whole_number_power
#define Error_Invalid_whole_number_rem
#define Error_Invalid_whole_number_intdiv
#define Error_Overflow_zero
static wholenumber_t abs(wholenumber_t n)
Definition: Numerics.hpp:115
static const wholenumber_t MAX_EXPONENT
Definition: Numerics.hpp:64
char * stripLeadingZeros(char *)
RexxNumberString * checkNumber(size_t digits)
static char * dividePower(char *AccumPtr, RexxNumberStringBase *Accum, char *Output, size_t NumberDigits)
static char * addMultiplier(char *, size_t, char *, int)
void adjustPrecision(char *, size_t)
RexxNumberString * Division(RexxNumberString *, unsigned int)
static char * multiplyPower(char *leftPtr, RexxNumberStringBase *left, char *rightPtr, RexxNumberStringBase *right, char *OutPtr, size_t OutLen, size_t NumberDigits)
RexxNumberString * clone()
RexxNumberString * Multiply(RexxNumberString *)
RexxNumberString * power(RexxObject *)
static char * subtractDivisor(char *data1, size_t length1, char *data2, size_t length2, char *result, int Mult)
RexxNumberString * prepareOperatorNumber(size_t, size_t, bool)
static size_t highBits(size_t)
bool messageSend(RexxString *, RexxObject **, size_t, size_t, ProtectedObject &, bool processUnknown=true)
virtual bool numberValue(wholenumber_t &result, size_t precision)
ssize_t wholenumber_t
Definition: rexx.h:230