NumberStringMath.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 okmath.c */
40 /* */
41 /* Arithemtic function for the NumberString Class */
42 /* */
43 /******************************************************************************/
44 #include <ctype.h>
45 #include <stdlib.h>
46 #include <string.h>
47 
48 #include "RexxCore.h"
49 #include "StringClass.hpp"
50 #include "NumberStringClass.hpp"
51 #include "ArrayClass.hpp"
52 #include "RexxActivity.hpp"
53 #include "BufferClass.hpp"
54 #include "NumberStringMath.hpp"
55 #include "ActivityManager.hpp"
56 #include "ProtectedObject.hpp"
57 
58 
59 RexxNumberString *RexxNumberString::maxMin(RexxObject **args, size_t argCount, size_t named_argCount, unsigned int operation)
60 /*********************************************************************/
61 /* Function: Process the MAX and MIN builtin functions and methods */
62 /*********************************************************************/
63 {
64  size_t arg;
65  RexxNumberString *compobj, *maxminobj;
66  RexxInteger *compResult;
67  RexxObject *nextObject;
68  size_t saveFuzz, saveDigits;
69 
70  if (argCount == 0) return this; /* any arguments to ccompare? */
71 
72  /* Get a reference to our current act*/
74 
75  saveFuzz = CurrentActivation->fuzz(); /* get the current fuzz and digits */
76  saveDigits = CurrentActivation->digits();
77  CurrentActivation->setFuzz(0); /* set the fuzz setting to 0 */
78 
79  /* assume 1st operand (self) is the */
80  /* one we want ! */
81  // NB: The min and max methods are defined as rounding the values to the
82  // current digits settings, which bypasses the LOSTDIGITS condition
83  maxminobj = this->prepareNumber(saveDigits, ROUND);
84  ProtectedObject p(maxminobj);
85  for (arg=0; arg < argCount; arg++)
86  { /* Loop through all args */
87  nextObject = args[arg]; /* Get next argument. */
88 
89  if (nextObject == OREF_NULL)
90  { /* Was this arg omitted? */
91  /* Yes, report the error. */
92  /* but restore the fuzz first */
93  CurrentActivation->setFuzz(saveFuzz);
94  if (operation == OT_MAX) /* doing a MAX operation? */
95  {
96  reportException(Error_Incorrect_call_noarg, CHAR_ORXMAX, OREF_positional, arg + 1);
97  }
98  else /* nope must be min. */
99  {
100  reportException(Error_Incorrect_call_noarg, CHAR_ORXMIN, OREF_positional, arg + 1);
101  }
102  }
103 
104  compobj = nextObject->numberString();/* get a numberstring object */
105  if (compobj != OREF_NULL)
106  { /* Was conversion sucessfull? */
107  /* get new comp object in right */
108  /* digits */
109  compobj = compobj->prepareOperatorNumber(saveDigits, saveDigits, ROUND);
110 
111  /* Just compare the two NumberStrings*/
112  /* See if new number is greater than*/
113  /* See if we have a new MAX */
114  if (operation == OT_MAX)
115  {
116  compResult = compobj->isGreaterThan(maxminobj);
117 
118  }
119  else
120  { /* must be looking for MIN */
121  /* is new less than old maxmin */
122  /* if so we have a new maxmin. */
123  compResult = compobj->isLessThan(maxminobj);
124  }
125 
126 
127  if (compResult == TheTrueObject)
128  { /* Do we have a new MAX/MIN ? */
129  /* Yes, no need to save old MAX/MIN */
130  /* assign and protect our next */
131  /* MAX/MIN */
132  p = compobj;
133  maxminobj = (RexxNumberString *)compobj;
134  }
135  }
136  else
137  { /* invalid object type. */
138  /* be sure we restore original Fuzz */
139  CurrentActivation->setFuzz(saveFuzz);
140  /* keep maxminobj around just a */
141  // jlf : few GC risk with new_integer because should be cached...
142  reportException(Error_Incorrect_method_number, OREF_positional, new_integer(arg + 1), args[arg]);
143  }
144  }
145  CurrentActivation->setFuzz(saveFuzz); /* be sure we restore original Fuzz */
146  /* We have already made a */
147  /* copy/converted the MaxMin object */
148  /* and it is adjusted to the correct */
149  /* precision, so we have nothing */
150  /* left to do. */
151  return maxminobj; /* now return it. */
152 }
153 
155  char *NumPtr) /* first digit to round up */
156 /*********************************************************************/
157 /* Function: Adjust a a number string object to correct NUMERIC */
158 /* DIGITS setting */
159 /*********************************************************************/
160 {
161  int carry, RoundNum;
162  size_t resultDigits;
163  wholenumber_t numVal;
164 
165  resultDigits = this->length; /* get number of digits in number */
166  NumPtr += this->length; /* point one past last digit, this */
167  /* gives us most significant digit of*/
168  /* digits being truncated. */
169 
170  if (*NumPtr-- >= 5 )
171  { /* is this digit grater_equal to 5 */
172  carry = 1; /* yes, we need to round up next dig */
173  while (carry && resultDigits-- > 0)
174  {/* do while we have carry and digits */
175  /* left to round up in number */
176  if (*NumPtr == 9) /* is this digit 9? */
177  {
178  RoundNum = 0; /* Yes, then this digit will be 0 */
179  }
180  else
181  {
182  RoundNum = *NumPtr + carry; /* Not 9, add 1 (carry) to digit */
183  carry = 0; /* no more carry. */
184  }
185  *NumPtr-- = (char)RoundNum; /* Set this digit in data area. */
186  }
187 
188  if (carry )
189  { /* Done will all numbers, do we still*/
190  /* have a carry (Did carry propogate */
191  /* all the way through? */
192  *++NumPtr = 1; /* yes, set high digit to 1 */
193  this->exp += 1; /* increment exponent by one. */
194  }
195  }
196 
197  /* At this point number is all setup,*/
198  /* Check for overflow */
199  numVal = this->exp + this->length - 1;
200  if (numVal > Numerics::MAX_EXPONENT)
201  {
203  }
204  /* Check for underflow. */
205  else if (this->exp < Numerics::MIN_EXPONENT)
206  {
208  }
209  return;
210 }
211 
213 /*********************************************************************/
214 /* Function: Adjust the precision of a number to the given digits */
215 /*********************************************************************/
216 {
217  wholenumber_t resultVal;
218  /* is length of number too big? */
219  if (this->length > NumDigits)
220  {
221  size_t extra = this->length - NumDigits;
222  this->length = NumDigits; /* Yes, make length equal precision */
223  this->exp += extra; /* adjust exponent by amount over */
224  this->mathRound(number); /* Round the adjusted number */
225  }
226 
227  /* Was number reduced to zero? */
228  if (*number == 0 && this->length == 1)
229  {
230  this->setZero(); /* Yes, make it so... */
231  }
232  else
233  {
234 
235  /* At this point number is all setup,*/
236  /* Check for overflow */
237  resultVal = this->exp + this->length - 1;
238  if (resultVal > Numerics::MAX_EXPONENT)
239  {
241  }
242  else if (this->exp < Numerics::MIN_EXPONENT)
243  { /* Check for underflow. */
245  }
246  }
247  return; /* just return to caller. */
248 }
249 
250 size_t RexxNumberString::highBits(size_t number)
251 /*********************************************************************/
252 /* Function: Determine high order bit position of an unsigned */
253 /* number setting. */
254 /*********************************************************************/
255 {
256  size_t HighBit;
257 
258  if (number == 0) /* is number 0? */
259  {
260  return 0; /* Yes, just return 0, no high bit */
261  }
262 
263  HighBit = LONGBITS; /* get number of digits in number */
264 
265  while ((number & HIBIT) == 0)
266  { /* loops though all bit positions */
267  /* until first 1 bit is found. */
268  number <<= 1; /* shift number one bit pos left. */
269  HighBit--; /* decrement i, high bit not found */
270  }
271 
272  return HighBit; /* return count. */
273 }
274 
276  char *NumPtr, /* pointer to number data */
277  char *result, /* result location */
278  size_t resultLen, /* result length */
279  size_t NumberDigits) /* required digits setting */
280 /*********************************************************************/
281 /* Function: Adjust the number data to be with the correct NUMERIC */
282 /* DIGITS setting. */
283 /*********************************************************************/
284 {
285  /* Remove all leading zeros */
286  NumPtr = this->stripLeadingZeros(NumPtr);
287 
288  /* is length of number too big? */
289  if (this->length > NumberDigits)
290  {
291  this->length = NumberDigits; /* Yes, make length equal precision */
292  /* adjust exponent by amount over */
293  this->exp += this->length - NumberDigits;
294  this->mathRound(NumPtr); /* Round the adjusted number */
295  }
296 
297  if (resultLen == 0) /* See if there is anything to copy? */
298  {
299  return result; /* Nope, just return result Pointer. */
300  }
301  else
302  {
303  /* Copy the data into the result area*/
304  /* and pointer to start of data */
305  return(char *)memcpy(((result + resultLen - 1) - this->length), NumPtr, this->length);
306  }
307 }
308 
310  char *AccumPtr) /* current accumulator position */
311 /*********************************************************************/
312 /* Function: Remove all leading zeros from a number */
313 /*********************************************************************/
314 {
315  /* while leading digit is zero and */
316  /* still data in object */
317  while (!*AccumPtr && this->length>1)
318  {
319  AccumPtr++; /* Point to next digit. */
320  this->length--; /* length od number is one less. */
321  }
322  return AccumPtr; /* return pointer to 1st non-zero */
323 }
324 
325 void RexxNumberString::adjustPrecision(char *resultPtr, size_t NumberDigits)
326 /*********************************************************************/
327 /* Function: Adjust the precision of a number to the given digits */
328 /*********************************************************************/
329 {
330  bool CopyData;
331  wholenumber_t resultVal;
332  /* resultPtr will either point to */
333  /* the actual result data or be */
334  /* NULL, if the data is already in */
335  /* result obj. */
336  if (resultPtr == NULL)
337  { /* Is resultPtr NULL, that is data */
338  /* already in result object? */
339  CopyData = false; /* Yes, don't copy data. */
340  /* have data pointer point to data in*/
341  resultPtr = this->number; /* The result object. */
342  }
343  else
344  {
345  CopyData = true; /* resultPtr not null, need to copy */
346  }
347  /* is length of number too big? */
348  if (this->length > NumberDigits)
349  {
350  size_t extra = this->length - NumberDigits;
351  this->length = NumberDigits; /* Yes, make length equal precision */
352  this->exp += extra; /* adjust exponent by amount over */
353  this->mathRound(resultPtr); /* Round the adjusted number */
354  }
355 
356  if (CopyData)
357  { /* only remove leading zeros if */
358  /* data note already in the object. */
359  /* remove any leading zeros */
360  resultPtr = this->stripLeadingZeros(resultPtr);
361  /* Move result data into object */
362  memcpy(this->number, resultPtr, (size_t)this->length);
363  }
364 
365  /* make sure this number has the correct numeric settings */
366  setNumericSettings(NumberDigits, number_form());
367 
368  if (!*resultPtr && this->length == 1) /* Was number reduced to zero? */
369  this->setZero(); /* Yes, make it so... */
370  else
371  {
372 
373  /* At this point number is all setup,*/
374  /* Check for overflow */
375  resultVal = this->exp + this->length - 1;
376  if (resultVal > Numerics::MAX_EXPONENT)
377  {
379  }
380  else if (this->exp < Numerics::MIN_EXPONENT)
381  { /* Check for underflow. */
383  }
384  }
385  return; /* just return to caller. */
386 }
387 
388 
389 RexxNumberString *RexxNumberString::prepareNumber(size_t NumberDigits, bool rounding)
390 /*********************************************************************/
391 /* Function: Create new copy of supplied object and make sure the */
392 /* number is computed to correct digits setting */
393 /*********************************************************************/
394 {
395  /* clone ourselves */
396  RexxNumberString *newObj = this->clone();
397  if (newObj->length > NumberDigits)
398  {
399  // NOTE: This version does NOT raise a LOSTDIGITS condition, since it
400  // is used for formatting results from functions that are used to create
401  // intentionally shortened numbers.
402 
403  /* adjust exponent by amount over */
404  /* precision */
405  newObj->exp += newObj->length - NumberDigits;
406  newObj->length = NumberDigits; /* make length equal precision */
407  if (rounding == ROUND)
408  { /* are we to perform rounding? */
409  /* Round the adjusted number */
410  newObj->mathRound(newObj->number);
411  }
412  }
413  /* make sure this has the correct settings */
414  newObj->setNumericSettings(NumberDigits, number_form());
415  return newObj; /* return new object to caller. */
416 }
417 
418 
419 /**
420  * Prepare an operator numberstring to a given length,
421  * raising a LOSTDIGITS condition if the starting number
422  * will cause lost digits
423  *
424  * @param targetLength
425  * The target preparation length (>= numberDigits)
426  * @param numberDigits
427  * The digits setting used to determine LOSTDIGITS conditions
428  * @param rounding Inidicates whether rounding is to be performed if the
429  * target object is longer than the targetLength
430  *
431  * @return A new number object no longer than the target length.
432  */
433 RexxNumberString *RexxNumberString::prepareOperatorNumber(size_t targetLength, size_t numberDigits, bool rounding)
434 /*********************************************************************/
435 /* Function: Create new copy of supplied object and make sure the */
436 /* number is computed to correct digits setting */
437 /*********************************************************************/
438 {
439  /* clone ourselves */
440  RexxNumberString *newObj = this->clone();
441  if (newObj->length > numberDigits)
442  { /* is the length larger than digits()*/
443  /* raise a numeric condition, may */
444  /* not return from this. */
445  reportCondition(OREF_LOSTDIGITS, (RexxString *)newObj);
446  if (newObj->length > targetLength)
447  {
448  /* adjust exponent by amount over */
449  /* precision */
450  newObj->exp += newObj->length - targetLength;
451  newObj->length = targetLength; /* make length equal precision */
452  if (rounding == ROUND)
453  { /* are we to perform rounding? */
454  /* Round the adjusted number */
455  newObj->mathRound(newObj->number);
456  }
457  }
458  }
459  /* make sure this has the correct settings */
460  newObj->setNumericSettings(numberDigits, number_form());
461  return newObj; /* return new object to caller. */
462 }
463 
464 
466  RexxNumberString *other, /* other addition/subtract target */
467  unsigned int operation, /* add or subtract operation */
468  size_t NumberDigits ) /* precision to use */
469 /*********************************************************************/
470 /* Function: Add or subtract two normalized numbers */
471 /*********************************************************************/
472 {
473  RexxNumberString *left, *right, *result, *temp1;
474  char *leftPtr,*rightPtr,*resultPtr;
475  char *resultBuffer = NULL;
476  int right_sign, carry, addDigit, rc;
477  wholenumber_t LadjustDigits, RadjustDigits;
478  wholenumber_t adjustDigits;
479  size_t ResultSize;
480  wholenumber_t aLeftExp, aRightExp, rightExp, leftExp, MinExp;
481  size_t rightLength, leftLength;
482  char resultBufFast[FASTDIGITS*2+1]; /* for fast allocation if default */
483  size_t maxLength = NumberDigits + 1;
484 
485  /* Make copies of the input object */
486  /* since we may need to adjust */
487  /* values, and make these new */
488  /*objects safe. */
489  left = this;
490  right = other;
491  leftExp = left->exp; /* maintain our own copy of exponent */
492  rightExp = right->exp; /* these may be adjusted below. */
493 
494  leftLength = left->length; /* maintain our own copy of lengths */
495  rightLength = right->length; /* these may be adjusted below. */
496 
497  if (leftLength > NumberDigits)
498  {
499  // raise a numeric condition, which might not return
500  reportCondition(OREF_LOSTDIGITS, (RexxString *)this);
501  if (leftLength > maxLength)
502  {
503  leftExp += leftLength - maxLength;
504  leftLength = maxLength;
505  }
506  }
507 
508  if (rightLength > NumberDigits)
509  {
510  // raise a numeric condition, which might not return
511  reportCondition(OREF_LOSTDIGITS, (RexxString *)other);
512  if (rightLength > maxLength)
513  {
514  /* not return from this. */
515  rightExp += rightLength - maxLength;
516  rightLength = maxLength;
517  }
518  }
519 
520 
521  if (leftExp <= rightExp) /* Find the smaller of the two exps. */
522  {
523  MinExp = leftExp;
524  }
525  else
526  {
527  MinExp = rightExp;
528  }
529 
530 
531  aLeftExp = leftExp - MinExp; /* Compute adjusted Left exponent */
532  aRightExp = rightExp - MinExp; /* Compute adjusted Right exponent */
533  right_sign = right->sign; /* make a copy of the right objs sign*/
534  /* Now check if either number is */
535  /* zero or has dominance over */
536  /* the other number. */
537  temp1=NULL;
538  if (left->sign==0)
539  { /* Is left number zero */
540  temp1=right; /* Yes, set up to return right */
541  }
542  else if (right->sign==0)
543  { /* Is right number zero ? */
544  temp1=left; /* Yes, Setup up to return left */
545 
546  /* Is the left number completely */
547  /* dominant, that is can the right */
548  /* number affect the outcome of the */
549  /* arithmetic operation? */
550  }
551  else if ((aLeftExp + (wholenumber_t)leftLength) > (wholenumber_t)(rightLength + NumberDigits))
552  {
553  temp1=left; /* Yes, so return the left number.*/
554  /* Is the right number completely */
555  /* dominant, that is can the left */
556  /* number affect the outcome of the */
557  /* arithmetic operation? */
558  }
559  else if ((aRightExp + (wholenumber_t)rightLength) > (wholenumber_t)(leftLength + NumberDigits))
560  {
561  temp1=right; /* Yes, so setup to return right */
562  }
563  /* Temp1 will either point to null */
564  /* or to the number object that */
565  /* should be returned as the result. */
566  /* A null means we really do need to */
567  /* do that math. */
568  if (temp1)
569  { /* Can we do a quick return? */
570  result = temp1->clone(); /* Yes, copy temp1 for result */
571 
572  /* are we doing subtraction and */
573  /* the right operand is our result? */
574  if ((temp1 == right) && (operation == OT_MINUS))
575  {
576  result->sign = -result->sign; /* yes, make sign of result oposite */
577  }
578  /* of the right operand. */
579  /* Get result into correct precision.*/
580  result->setupNumber();
581  return result; /* and return new result object */
582  }
583  /* We really need to perfrom the */
584  /* arithmetic, so lets do it. */
585  if (operation == OT_MINUS)
586  { /* is this a subtraction request? */
587  right_sign = -right_sign; /* yes, invert sign of right number */
588  /* to make addition. */
589  }
590 
591  if (right_sign != left->sign)
592  { /* are the two signs equal? */
593  /* nope, see if numbers are equal? */
594  if (((leftLength == rightLength) && (leftExp == rightExp)) &&
595  !(memcmp(left->number, right->number, leftLength)) )
596  {
597 
598  return new_numberstring("0", 1); /* Yes, return Zero as result. */
599  }
600  operation = OT_MINUS; /* We are now doing a subtraction. */
601  }
602  else
603  { /* signs are equal, it is addition */
604  operation = OT_PLUS; /* We will now do a addition. */
605  }
606 
607  ResultSize = maxLength; /* size will be NUMERIC DIGITS + 1 */
608  result = (RexxNumberString *) new (ResultSize) RexxNumberString (ResultSize);
609 
610  result->sign = 0; /* make sure all values are zero */
611  result->exp=0; /* to start with ... */
612  result->length=0;
613 
614  /* LeftPtr points to end of number */
615  leftPtr = left->number + leftLength - 1;
616  /* RightPtr points to end of number */
617  rightPtr = right->number + rightLength - 1;
618  resultPtr = NULL; /* Initialize Result Ptr to 0; */
619 
620 
621  /* See if we need oto adjust the */
622  /* number with respect to current */
623  /* Digits setting. */
624  /* Compute the amount we may need to */
625  /* adjust for each number. Using the */
626  /* Adjusted exponents .... */
627  /* a value of 0 or less means we are */
628  /*OK. */
629  LadjustDigits = ((wholenumber_t)leftLength + aLeftExp) - (wholenumber_t)(maxLength);
630  RadjustDigits = ((wholenumber_t)rightLength + aRightExp) - (wholenumber_t)(maxLength);
631  /* Do we need to adjust any numbers? */
632  if (LadjustDigits > 0 || RadjustDigits >0 )
633  {
634  if (LadjustDigits >= RadjustDigits) /* yes, find which number needs to be*/
635  {
636  /* adjusted the most and assign the */
637  adjustDigits = LadjustDigits; /* adjustment value to adjustDigits. */
638  }
639  else
640  {
641  adjustDigits = RadjustDigits;
642  }
643  /* now we adjust the adjust exp */
644  /* and real length/exp of each no. */
645 
646 
647  if (aLeftExp)
648  { /* Was left exp larger than right */
649  if ((wholenumber_t)adjustDigits < aLeftExp)
650  { /* Do we need to adjust for more than*/
651  /* our adjusted exponent? */
652  aLeftExp -= adjustDigits; /* Yes, decrease adj exp */
653  /* Right number is now shorter */
654  rightPtr = rightPtr-adjustDigits;
655  rightExp += adjustDigits; /* Right exponent adjusted */
656  rightLength -= adjustDigits; /* update the length to reflect */
657  adjustDigits = 0; /* adjustment done. */
658  }
659  else
660  { /* decrease by adjusted exp value */
661  /* Right number is now shorter */
662  rightPtr = rightPtr-aLeftExp;
663  rightExp += aLeftExp; /* Right exponent adjusted */
664  rightLength -= adjustDigits; /* update the length to reflect */
665  adjustDigits -= aLeftExp; /* adjustment partially done. */
666  aLeftExp = 0; /* the adjusted exponent is now zero.*/
667  }
668  }
669  else if (aRightExp)
670  { /* Was right exp larger than left */
671  if ((wholenumber_t)adjustDigits < aRightExp)
672  { /* Do we adjust for more than */
673  /* our adjusted exponent? */
674  aRightExp -= adjustDigits; /* Yes, decrease adj exp */
675  /* Left number is now shorter */
676  leftPtr = leftPtr-adjustDigits;
677  leftExp += adjustDigits; /* Left exponent adjusted */
678  leftLength -= adjustDigits; /* update the length to reflect */
679  adjustDigits = 0; /* adjustment done. */
680  }
681  else
682  { /* decrease by adjusted exp value */
683  /* Right number is now shorter */
684  leftPtr = leftPtr-aRightExp;
685  leftExp += aRightExp; /* Right exponent adjusted */
686  leftLength -= adjustDigits; /* update the length to reflect */
687  adjustDigits -= aRightExp; /* adjustment partially done. */
688  aRightExp = 0; /* the adjusted exponent is now zero.*/
689  }
690  }
691 
692  if (adjustDigits)
693  { /* Is there still adjusting needed */
694  leftExp += adjustDigits; /* So adjust length and exp of each */
695  /* bumber by the remaining adjust */
696  leftPtr = leftPtr-adjustDigits;
697  rightExp += adjustDigits;
698  rightPtr = rightPtr - adjustDigits;
699  }
700  } /* Done with adjusting the numbers, */
701  if (NumberDigits <= FASTDIGITS) /* Get a buffer for the reuslt */
702  {
703  resultBuffer = resultBufFast;
704  }
705  else
706  {
707  resultBuffer = buffer_alloc(NumberDigits*2 + 1);
708  }
709 
710  /* Have Result Ptr point to end */
711  resultPtr = resultBuffer + NumberDigits*2;
712 
713  if (operation == OT_PLUS)
714  { /* Are we doing addition? */
715  carry = 0; /* no carry to start with. */
716 
717  /* we need check and see if there */
718  /* are values in the adjusted exps */
719  /* that is do we pretend there */
720  /* are extra zeros at the end */
721  /* of the numbers? */
722  result->sign = left->sign; /* we are doing addition, both signs */
723  /* are the same, assign use left for */
724  /* result. */
725  if (aLeftExp)
726  {
727  while (aLeftExp--)
728  { /* does left need zeros "added"? */
729  /* yes, move digits of right */
730  /* number into result */
731  /* xxxxxxx000 <- aLeftExp = 3 */
732  /* yyyyyyyyy <- aRightExp = 0 */
733  if (rightPtr >= right->number) /* Is there still data to move? */
734  {
735  *resultPtr-- = *rightPtr--; /* Yes, move in correct digit. */
736  }
737  else /* nope, */
738  {
739  *resultPtr-- = '\0'; /* nope, move in a zero. we remove */
740  }
741  /* leading zeros from orig number */
742  result->length++; /* Length is one greater. */
743  }
744  result->exp = rightExp; /* Right is smaller, assign to resul */
745  }
746  else if (aRightExp)
747  {
748  while (aRightExp--)
749  { /* does right need zeros "added"? */
750  /* yes, move digits of left */
751  /* number into result */
752  /* xxxxxxxxx <- aLeftExp = 0 */
753  /* yyyyyy00 <- aRightExp = 2 */
754 
755  if (leftPtr >= left->number) /* Is there still data to move? */
756  {
757  *resultPtr-- = *leftPtr--; /* Yes, move in correct digit. */
758  }
759  else /* nope, */
760  {
761  *resultPtr-- = '\0'; /* nope, move in a zero. */
762  }
763  result->length++; /* Result length is now one more. */
764  }
765  result->exp = leftExp; /* left is smaller, assign to result */
766  }
767  else
768  {
769  result->exp = leftExp; /* otherwise same exp. take left */
770  }
771 
772  while ( (leftPtr >= left->number) &&/* While we still have data to add. */
773  (rightPtr >= right->number) )
774  {
775  /* add the two current digits with a */
776  /* possibly carry bit, and update the*/
777  /* left and right ptr to point to */
778  /* next (actually previous) digit. */
779  addDigit = carry + (*leftPtr--) + *(rightPtr--);
780  if (addDigit >= 10)
781  { /* result greater than 10? we have a */
782  /* carry for our next addition. */
783  carry = 1; /* indicate carry. */
784  addDigit -= 10; /* subtract 10 from our result. */
785  }
786  else
787  { /* not bigger than 10. */
788  carry = 0; /* cancel any former carry */
789  }
790  *resultPtr-- = (char)addDigit; /* move result into the result */
791  result->length++; /* length of result is one more. */
792  } /* go back and do next set of digits */
793 
794  /* One of the numbers is finished, */
795  /* check the other. */
796 
797  while (leftPtr >= left->number)
798  { /* While still digits in the */
799  /* left number. */
800  addDigit = carry + (*leftPtr--); /* add in any carry, and move to */
801  /* next digit to add. */
802  if (addDigit >= 10)
803  { /* do we still have a carry */
804  carry = 1; /* yes, indicate carry. */
805  addDigit -= 10; /* subtract 10 from our result. */
806  }
807  else
808  { /* not bigger than 10. */
809  carry = 0; /* make sure we cancel former carry */
810  }
811  *resultPtr-- = (char)addDigit; /* move result into the result */
812  result->length++; /* length of result is one more. */
813  } /* all done with left number. */
814 
815  while (rightPtr >= right->number)
816  { /* While there is still digits in */
817  /* right number. */
818  addDigit = carry + (*rightPtr--); /* add in any carry, and move to the */
819  /* next digit to add. */
820  if (addDigit >= 10)
821  { /* do we still have a carry */
822  carry = 1; /* indicate carry. */
823  addDigit -= 10; /* subtract 10 from our result. */
824  }
825  else
826  { /* not bigger than 10. */
827  carry = 0; /* make sure we cancel former carry */
828  }
829  *resultPtr-- = (char)addDigit; /* move result into the result */
830  result->length++; /* length of result is one more. */
831  } /* all done with left number. */
832 
833  if (carry)
834  { /* Do we still have a carry over? */
835  result->length++; /* yes, number is now one more */
836  *resultPtr-- = 1; /* set the high digit to 1. */
837  }
838  } /* end of addition. */
839 
840  else
841  { /* we are doing subtraction. */
842 
843  /* is left number bigger than right */
844  if ((aLeftExp + leftLength)>(aRightExp + rightLength))
845  {
846  /* yes, subtract right from left */
847  subtractNumbers(left, leftPtr, aLeftExp, right, rightPtr, aRightExp, result, &resultPtr);
848  /* result exp is the adjusted exp of */
849  /* smaller number. */
850  if (aLeftExp) /* if adjusted left exp has a value */
851  {
852  result->exp = rightExp; /* the the right exp was smaller */
853  }
854  else
855  {
856  result->exp = leftExp; /* otherwise left was smaller/equal */
857  }
858 
859  result->sign = left->sign; /* result sign is that of left. */
860  }
861  /* is right number bigger than left */
862  else if ((aLeftExp + leftLength)<(aRightExp + rightLength))
863  {
864  /* yes, subtract left from right */
865  subtractNumbers(right, rightPtr, aRightExp, left, leftPtr, aLeftExp, result, &resultPtr);
866  /* result exp is adjusted exp of the */
867  /* smaller number. */
868  if (aLeftExp) /* if adjusted left exp has a value */
869  {
870  result->exp = rightExp; /* the the right exp was smaller */
871  }
872  else
873  {
874  result->exp = leftExp; /* otherwise left was smaller/equal */
875  }
876 
877  result->sign = right_sign; /* result sign is that of right. */
878  }
879 
880  /* here both numbers have same */
881  /* adjusted lexponent + length */
882  /* so see which number is longer and */
883  /* each number for length of smaller.*/
884  /* if they compare equal the result */
885  /* is zero */
886  else if (rightLength < leftLength)
887  {/* Does right number have a smaller */
888  /* length. */
889 
890  /* Yes, compare the digits.... */
891  /* and see if right is larger. */
892  if ((rc = memcmp(right->number, left->number, rightLength)) > 0)
893  {
894  /* yes, subtract left from right */
895  subtractNumbers(right, rightPtr, aRightExp, left, leftPtr, aLeftExp, result, &resultPtr);
896  result->sign = right_sign; /* result sign is that of right. */
897  }
898  else
899  {
900  /* no, subtract right from left */
901  subtractNumbers(left, leftPtr, aLeftExp, right, rightPtr, aRightExp, result, &resultPtr);
902  result->sign = left->sign; /* result sign is that of left. */
903  }
904  result->exp = leftExp; /* result exp is that of the longer */
905  /* number (smaller Exp.) which is the*/
906  /* left number in this case. */
907  }
908  else
909  { /* left length is smaller or equal to*/
910  /* the length of right. */
911  /* see if left number is larger */
912  if ((rc = memcmp(left->number, right->number, leftLength)) > 0)
913  {
914  /* yes, subtract right from left */
915  subtractNumbers(left, leftPtr, aLeftExp, right, rightPtr, aRightExp, result, &resultPtr);
916  result->exp = rightExp; /* result exp is that of the longer */
917  /* number (smaller Exp.) which is */
918  /* right number in this case. */
919 
920  result->sign = left->sign; /* result sign is that of left. */
921  }
922  else if (rc)
923  { /* is the right number larger? */
924  /* no, subtract left from right */
925  subtractNumbers(right, rightPtr, aRightExp, left, leftPtr, aLeftExp, result, &resultPtr);
926  result->exp = rightExp; /* result exp is that of the longer */
927  /* number (smaller Exp.) which is the*/
928  /* right number in this case. */
929  result->sign = right_sign; /* result sign is that of right. */
930  }
931  else
932  { /* numbers compared are equal. */
933  if (leftLength < rightLength)
934  { /* does left have fewer digits? */
935  /* Yes, then left is actuall smaller */
936  /* so subtract left from right */
937  subtractNumbers(right, rightPtr, aRightExp, left, leftPtr, aLeftExp, result, &resultPtr);
938  result->exp = rightExp; /* result exp is that of the longer */
939  /* number (smaller Exp.) which is */
940  /* left number in this case. */
941  result->sign = right_sign; /* result sign is that of right. */
942  }
943  else
944  { /* Lengths are also eqaul, so numbers*/
945  /* are identical. */
946  result->sign=0; /* number equal, return 0 */
947  result->exp = 0;
948  result->length = 1;
949  result->number[0] = '0';
950  }
951  }
952  }
953  } /* End of subtraction. */
954 
955  /* pointer resultPtr always points */
956  /* to next position to add a digit */
957  /* thereofre we will bump the pointer*/
958  /* 1st before doing any cleanup */
959  /* we end up pointing to the most sig*/
960  /* digit on exit of loop instead of */
961  /* the 1st digit. */
962 
963  /*make sure result end up with */
964  /* correct precision. */
965  result->adjustPrecision(++resultPtr, NumberDigits);
966  return result; /* all done, return the result */
967 
968 }
969 
971  RexxNumberString *larger, /* larger numberstring object */
972  const char *largerPtr, /* pointer to last digit in larger */
973  wholenumber_t aLargerExp, /* adjusted exponent of larger */
974  RexxNumberString *smaller, /* smaller numberstring object */
975  const char *smallerPtr, /* pointer to last digit in smaller */
976  wholenumber_t aSmallerExp, /* adjusted exponent of smaller */
977  RexxNumberString *result, /* result numberstring object */
978  char **presultPtr) /* last number in result */
979 /*********************************************************************/
980 /* Function: Subtract two numbers. The second number is subtracted */
981 /* from the first. The absolute value of the 1st number */
982 /* must be larger than the absolute value of the second. */
983 /*********************************************************************/
984 {
985  int borrow, subDigit;
986  char *resultPtr;
987 
988  resultPtr = *presultPtr; /* since we need to update value of */
989  /* resultPtr and return value to */
990  /* caller, we are passed a pointer */
991  /* pointer, we'll just use Ptr to */
992  /* data. (avoid reference problems) */
993  /* we will update this pointer value */
994  /* before exiting, so the Ptr */
995  /* is correct in caller. */
996  borrow = 0; /* no carry to start with. */
997 
998  /* 1st we need to make both adjusted */
999  /* exponents zero. values are either*/
1000  /* positive or zero on entry. */
1001  /* one of the adjusted exponents will*/
1002  /* always be zero on entry. */
1003  while (aLargerExp--)
1004  { /* if larger number had a value for */
1005  /* for adjusted exponent that means */
1006  /* that smaller number had a smaller */
1007  /* exponent (less significant digit */
1008  /* so we pretend to add extra zeros */
1009  /* to the larger number and do the */
1010  /* subtraction for required number */
1011  /* of digits, (aLargerExp). */
1012  /* xxxxx00 */
1013  /* yyyyyy */
1014 
1015  if (smallerPtr >= smaller->number) /* Is there still data to subtract */
1016  {
1017  subDigit = *smallerPtr--; /* Yes, set value for subtraction */
1018  }
1019  else /* nope, */
1020  {
1021  subDigit = '\0'; /* nope, use a Zero for subtraction. */
1022  }
1023 
1024  /* subtract 10 from smaller number, */
1025  /* any borrow. */
1026  /* and point to next digit. */
1027  subDigit = borrow + 10 - subDigit;
1028  if (subDigit == 10)
1029  { /* was result 10, this can only occur*/
1030  /* the bottom digit was a zero and we*/
1031  /* didn't borrow anyting. */
1032  subDigit -= 10; /* Yes, result will be zero and */
1033  borrow = 0; /* no borrow. */
1034  }
1035  else
1036  {
1037  borrow = -1; /* nope, result digit ok, and we */
1038  }
1039  /* need to borrow. */
1040  *resultPtr-- = (char)subDigit; /* place this digit in result number */
1041  result->length++; /* length of result is now one more. */
1042  }
1043 
1044  while (aSmallerExp--)
1045  { /* if smaller number had a value for */
1046  /* for adjusted exponent that means */
1047  /* that larger number had a smaller */
1048  /* exponent (more significant digit */
1049  /* so we pretend to add extra zeros */
1050  /* to smaller number and do the */
1051  /* subtraction for required number */
1052  /* of digits, (aSmallerExp). */
1053  /* xxxxxxx */
1054  /* yyyy00 */
1055 
1056  /* here we just move the the digits */
1057  /* from larger into result. */
1058  /* and point to next digit. */
1059 
1060  if (largerPtr >= larger->number) /* Is there still data to move? */
1061  {
1062  *resultPtr-- = *largerPtr--; /* Yes, move in correct digit. */
1063  }
1064  else /* nope, */
1065  {
1066  *resultPtr-- = '\0'; /* nope, move in a zero. we remove */
1067  }
1068  /* leading zeros from orig number */
1069  result->length++; /* length of result is now one more. */
1070  }
1071 
1072  /* Now we are ready to do subtract */
1073  /* of our digits. */
1074  /* While still have data to subtract */
1075  while (smallerPtr >= smaller->number)
1076  {
1077  /* Sub two current digits with a */
1078  /* possibly borrow bit, and update */
1079  /* larger and smaller pointer to */
1080  /* to next (actually previous) digit */
1081  subDigit = borrow + (*largerPtr--) - *(smallerPtr--);
1082  if (subDigit < 0 )
1083  { /* result less than 0, Do we need to */
1084  /* borrow for next subtraction */
1085  borrow = -1; /* yes, indicate borrow. */
1086  subDigit += 10; /* add 10 to result from borrow. */
1087  }
1088  else
1089  { /* not less than 0 */
1090  borrow = 0; /* make sure we cancel former borrow */
1091  }
1092  *resultPtr-- = (char)subDigit; /* move result into result object. */
1093  result->length++; /* length of result is one more. */
1094  } /* go back and do next set of digits */
1095 
1096  /* One number is finished, need */
1097  /* to check the other. */
1098 
1099  while (largerPtr >= larger->number)
1100  {/* While still digits in the larger */
1101  subDigit = borrow + (*largerPtr--);/* sub any borrow, and move to the */
1102  /* next digit to subtract. */
1103  if (subDigit < 0 )
1104  { /* do we still need to borrow? */
1105  borrow = -1; /* yes, indicate borrow */
1106  subDigit += 10; /* add 10 to result for borrow. */
1107  }
1108  else
1109  { /* not bigger than 10. */
1110  borrow = 0; /* make sure we cancel former carry */
1111  }
1112  *resultPtr-- = (char)subDigit; /* move result into result object. */
1113  result->length++; /* length of result is one more. */
1114  } /* all done with larger number. */
1115 
1116  *presultPtr = resultPtr; /* update result PTR for our return */
1117  return;
1118 }
1119 
1121  int Digit, /* digit to add */
1122  char *Value, /* number to add */
1123  char *HighDigit ) /* highest digit location */
1124 /*********************************************************************/
1125 /* Function: Adds a base ten digit to string number in */
1126 /* base 16 (used by the d2x and d2c functions) */
1127 /*********************************************************************/
1128 {
1129  while (Digit)
1130  { /* while something to add */
1131  Digit += *Value; /* add in current number */
1132  if (Digit > 15)
1133  { /* carry? */
1134  Digit -= 16; /* reduce digit */
1135  *Value-- = (char)Digit; /* set digit and step pointer */
1136  Digit = 1; /* just a carry digit now */
1137  }
1138  else
1139  {
1140  *Value-- = (char)Digit; /* set the digit */
1141  Digit = 0; /* no more carry */
1142  }
1143  }
1144  if (Value < HighDigit) /* new high water mark? */
1145  {
1146  return Value; /* return high location */
1147  }
1148  else
1149  {
1150  return HighDigit; /* return the old one */
1151  }
1152 }
1153 
1155  char * Accum, /* number to multiply */
1156  char * HighDigit ) /* current high water mark */
1157 /*********************************************************************/
1158 /* Function: multiplies a base 16 number by 10, placing */
1159 /* the result in the same buffer. */
1160 /*********************************************************************/
1161 {
1162  int Carry; /* multiplication carry */
1163  unsigned int Digit; /* current digit */
1164  char * OutPtr; /* output pointer */
1165 
1166  OutPtr = Accum; /* point to first digit */
1167  Carry = 0; /* no carry yet */
1168  while (OutPtr > HighDigit)
1169  { /* while more digits */
1170  /* multiply digit by 10 */
1171  Digit = (unsigned int )((*OutPtr * 10) + Carry);
1172  if (Digit > 15)
1173  { /* carry? */
1174  Carry = (int)(Digit / 16); /* get carry value */
1175  Digit &= (unsigned int )0x0000000f; /* keep just lower nibble */
1176  }
1177  else /* no carry here */
1178  {
1179  Carry = 0; /* no carry */
1180  }
1181  *OutPtr-- = (char)Digit; /* set the digit */
1182  }
1183  if (Carry) /* carried out? */
1184  {
1185  *OutPtr-- = (char)Carry; /* set the carry pointer */
1186  }
1187  return OutPtr; /* return new high water mark */
1188 }
1189 
1191  int Digit, /* digit to add */
1192  char *Accum, /* number to add */
1193  char *HighDigit ) /* highest digit location */
1194 /*********************************************************************/
1195 /* Function: Adds a base sixteen digit to a string number */
1196 /* base 10 (used by the d2x and d2c functions) */
1197 /*********************************************************************/
1198 {
1199  int Carry; /* carry number */
1200 
1201  Carry = 0; /* no carry yet */
1202  while (Digit || Carry)
1203  { /* while something to add */
1204  Digit += *Accum + Carry; /* add in current number */
1205  if (Digit > 9)
1206  { /* carry? */
1207  Carry = Digit / 10; /* get the carry out */
1208  Digit %= 10; /* reduce digit */
1209  *Accum-- = (char)Digit; /* set digit and step pointer */
1210  }
1211  else
1212  {
1213  *Accum-- = (char)Digit; /* set the digit */
1214  Carry = 0; /* no more carry */
1215  }
1216  Digit = 0; /* no addition after first */
1217  }
1218  if (Accum < HighDigit) /* new high water mark? */
1219  {
1220  return Accum; /* return high location */
1221  }
1222  else
1223  {
1224  return HighDigit; /* return the old one */
1225  }
1226 }
1227 
1229  char * Accum, /* number to multiply */
1230  char * HighDigit ) /* current high water mark */
1231 
1232 /*********************************************************************/
1233 /* Function: multiplies a base 16 number by 10, placing */
1234 /* the number in a different buffer. */
1235 /*********************************************************************/
1236 {
1237  char * OutPtr; /* addition pointer */
1238  int Carry; /* multiplication carry */
1239  unsigned int Digit; /* current digit */
1240 
1241  OutPtr = Accum; /* point to output buffer */
1242  Carry = 0; /* no carry yet */
1243 
1244  while (OutPtr > HighDigit)
1245  { /* while more digits */
1246  /* multiply digit by 16 */
1247  Digit = (unsigned int )((*OutPtr * 16) + Carry);
1248  if (Digit > 9)
1249  { /* carry? */
1250  Carry = (int)(Digit / 10); /* get carry value */
1251  Digit %= 10; /* get the digit value */
1252  }
1253  else /* no carry here */
1254  {
1255  Carry = 0; /* no carry */
1256  }
1257  *OutPtr-- = (char)Digit; /* set the digit */
1258  }
1259  while (Carry)
1260  { /* carried out? */
1261  Digit = Carry % 10; /* get first carry digit */
1262  Carry = Carry / 10; /* get the next digit */
1263  *OutPtr-- = (char)Digit; /* set the digit */
1264  }
1265  return OutPtr; /* return new high water mark */
1266 }
void reportCondition(RexxString *condition, RexxString *description)
void reportException(wholenumber_t error)
RexxInteger * new_integer(wholenumber_t v)
RexxNumberString * new_numberstring(const char *s, stringsize_t l)
#define LONGBITS
#define OT_PLUS
#define FASTDIGITS
#define OT_MINUS
#define OT_MAX
#define buffer_alloc(s)
#define ROUND
#define HIBIT
bool number_form()
Definition: Numerics.hpp:157
#define OREF_NULL
Definition: RexxCore.h:60
#define TheTrueObject
Definition: RexxCore.h:186
#define Error_Incorrect_method_number
#define Error_Incorrect_call_noarg
#define Error_Overflow_expoverflow
#define Error_Overflow_expunderflow
static RexxActivity *volatile currentActivity
static const wholenumber_t MIN_EXPONENT
Definition: Numerics.hpp:65
static const wholenumber_t MAX_EXPONENT
Definition: Numerics.hpp:64
static const size_t DEFAULT_DIGITS
Definition: Numerics.hpp:66
virtual void setFuzz(size_t)
virtual size_t digits()
virtual size_t fuzz()
RexxActivationBase * getTopStackFrame()
char * stripLeadingZeros(char *)
char * adjustNumber(char *, char *, size_t, size_t)
static char * addToBaseTen(int, char *, char *)
RexxInteger * isLessThan(RexxObject *)
RexxNumberString * prepareNumber(size_t, bool)
RexxInteger * isGreaterThan(RexxObject *)
void adjustPrecision(char *, size_t)
static char * multiplyBaseSixteen(char *, char *)
RexxNumberString * clone()
RexxNumberString * maxMin(RexxObject **, size_t, size_t, unsigned int)
RexxNumberString * prepareOperatorNumber(size_t, size_t, bool)
static void subtractNumbers(RexxNumberString *larger, const char *largerPtr, wholenumber_t aLargerExp, RexxNumberString *smaller, const char *smallerPtr, wholenumber_t aSmallerExp, RexxNumberString *result, char **resultPtr)
void setNumericSettings(size_t digits, bool form)
static size_t highBits(size_t)
static char * addToBaseSixteen(int, char *, char *)
static char * multiplyBaseTen(char *, char *)
RexxNumberString * addSub(RexxNumberString *, unsigned int, size_t)
RexxNumberString * numberString()
ssize_t wholenumber_t
Definition: rexx.h:230