------------------------------------------------------------------ */ decUnitAddSub -- add or subtract two >=0 integers in Unit arrays */ / This routine performs the calculation: */ / C=A+(B*M) */ / Where M is in the range -DECDPUNMAX through +DECDPUNMAX. */ / A may be shorter or longer than B.
| 6333 | /* (IBM Warwick, UK) for some of the ideas used in this routine. */ |
| 6334 | /* ------------------------------------------------------------------ */ |
| 6335 | static Int decUnitAddSub(const Unit *a, Int alength, |
| 6336 | const Unit *b, Int blength, Int bshift, |
| 6337 | Unit *c, Int m) { |
| 6338 | const Unit *alsu=a; // A lsu [need to remember it] |
| 6339 | Unit *clsu=c; // C ditto |
| 6340 | Unit *minC; // low water mark for C |
| 6341 | Unit *maxC; // high water mark for C |
| 6342 | eInt carry=0; // carry integer (could be Long) |
| 6343 | Int add; // work |
| 6344 | #if DECDPUN<=4 // myriadal, millenary, etc. |
| 6345 | Int est; // estimated quotient |
| 6346 | #endif |
| 6347 | |
| 6348 | #if DECTRACE |
| 6349 | if (alength<1 || blength<1) |
| 6350 | printf("decUnitAddSub: alen blen m %ld %ld [%ld]\n", alength, blength, m); |
| 6351 | #endif |
| 6352 | |
| 6353 | maxC=c+alength; // A is usually the longer |
| 6354 | minC=c+blength; // .. and B the shorter |
| 6355 | if (bshift!=0) { // B is shifted; low As copy across |
| 6356 | minC+=bshift; |
| 6357 | // if in place [common], skip copy unless there's a gap [rare] |
| 6358 | if (a==c && bshift<=alength) { |
| 6359 | c+=bshift; |
| 6360 | a+=bshift; |
| 6361 | } |
| 6362 | else for (; c<clsu+bshift; a++, c++) { // copy needed |
| 6363 | if (a<alsu+alength) *c=*a; |
| 6364 | else *c=0; |
| 6365 | } |
| 6366 | } |
| 6367 | if (minC>maxC) { // swap |
| 6368 | Unit *hold=minC; |
| 6369 | minC=maxC; |
| 6370 | maxC=hold; |
| 6371 | } |
| 6372 | |
| 6373 | // For speed, do the addition as two loops; the first where both A |
| 6374 | // and B contribute, and the second (if necessary) where only one or |
| 6375 | // other of the numbers contribute. |
| 6376 | // Carry handling is the same (i.e., duplicated) in each case. |
| 6377 | for (; c<minC; c++) { |
| 6378 | carry+=*a; |
| 6379 | a++; |
| 6380 | carry+=((eInt)*b)*m; // [special-casing m=1/-1 |
| 6381 | b++; // here is not a win] |
| 6382 | // here carry is new Unit of digits; it could be +ve or -ve |
| 6383 | if ((ueInt)carry<=DECDPUNMAX) { // fastpath 0-DECDPUNMAX |
| 6384 | *c=(Unit)carry; |
| 6385 | carry=0; |
| 6386 | continue; |
| 6387 | } |
| 6388 | #if DECDPUN==4 // use divide-by-multiply |
| 6389 | if (carry>=0) { |
| 6390 | est=(((ueInt)carry>>11)*53687)>>18; |
| 6391 | *c=(Unit)(carry-est*(DECDPUNMAX+1)); // remainder |
| 6392 | carry=est; // likely quotient [89%] |
no outgoing calls
no test coverage detected