зеркало из https://github.com/mozilla/gecko-dev.git
637 строки
20 KiB
C++
637 строки
20 KiB
C++
/* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version 1.1 (the
|
|
* "License"); you may not use this file except in compliance with the License. You may obtain
|
|
* a copy of the License at http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
|
|
* WARRANTY OF ANY KIND, either express or implied. See the License for the specific
|
|
* language governing rights and limitations under the License.
|
|
*
|
|
* The Original Code is [Open Source Virtual Machine.]
|
|
*
|
|
* The Initial Developer of the Original Code is Adobe System Incorporated. Portions created
|
|
* by the Initial Developer are Copyright (C)[ 1993-2006 ] Adobe Systems Incorporated. All Rights
|
|
* Reserved.
|
|
*
|
|
* Contributor(s): Adobe AS3 Team
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of either the GNU
|
|
* General Public License Version 2 or later (the "GPL"), or the GNU Lesser General Public
|
|
* License Version 2.1 or later (the "LGPL"), in which case the provisions of the GPL or the
|
|
* LGPL are applicable instead of those above. If you wish to allow use of your version of this
|
|
* file only under the terms of either the GPL or the LGPL, and not to allow others to use your
|
|
* version of this file under the terms of the MPL, indicate your decision by deleting provisions
|
|
* above and replace them with the notice and other provisions required by the GPL or the
|
|
* LGPL. If you do not delete the provisions above, a recipient may use your version of this file
|
|
* under the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
***** END LICENSE BLOCK ***** */
|
|
|
|
|
|
|
|
#include <math.h>
|
|
|
|
#include "avmplus.h"
|
|
#include "BigInteger.h"
|
|
|
|
#define X86_MATH
|
|
namespace avmplus
|
|
{
|
|
|
|
|
|
void BigInteger::setFromDouble(double value)
|
|
{
|
|
int e;
|
|
uint64 mantissa = MathUtils::frexp(value,&e); // value = mantissa*2^e, mantissa and e are integers.
|
|
numWords = (2 + ((e > 0 ? e : -e) /32));
|
|
|
|
AvmAssert(numWords <= kMaxBigIntegerBufferSize);
|
|
wordBuffer[1] = (uint32)(mantissa >> 32);
|
|
wordBuffer[0] = (uint32)(mantissa & 0xffffffff);
|
|
numWords = (wordBuffer[1] == 0 ? 1 : 2);
|
|
|
|
if(e < 0)
|
|
rshiftBy(-e);
|
|
else
|
|
lshiftBy(e);
|
|
}
|
|
|
|
void BigInteger::setFromBigInteger(const BigInteger* from, int32 offset, int32 amount)
|
|
{
|
|
numWords = amount;
|
|
AvmAssert(numWords <= kMaxBigIntegerBufferSize);
|
|
memcpy( (byte*)wordBuffer,
|
|
(byte*)&(from->wordBuffer[offset]),
|
|
amount*sizeof(uint32));
|
|
}
|
|
|
|
double BigInteger::doubleValueOf() const
|
|
{
|
|
// todo: there's got to be a quicker/smaller code alg for this.
|
|
if (numWords == 1)
|
|
return (double)wordBuffer[0];
|
|
|
|
// determine how many of bits are used by the top word
|
|
int bitsInTopWord=1;
|
|
for(uint32 topWord = wordBuffer[numWords-1]; topWord > 1; topWord >>= 1)
|
|
bitsInTopWord++;
|
|
|
|
// start result with top word. We will accumulate the most significant 53 bits of data into it.
|
|
int nextWord = numWords-1;
|
|
|
|
// used for rounding:
|
|
bool bit53 = false;
|
|
bool bit54 = false;
|
|
bool rest = false;
|
|
|
|
const uint64 ONEL = 1UL;
|
|
uint64 resultMantissa = 0;
|
|
uint64 w = 0;
|
|
int pos = 53;
|
|
int bits = bitsInTopWord;
|
|
int wshift = 0;
|
|
while(pos > 0)
|
|
{
|
|
// extract word and | it in
|
|
w = wordBuffer[nextWord--];
|
|
resultMantissa |= (w >> wshift);
|
|
pos -= bits;
|
|
|
|
if (pos > 0)
|
|
{
|
|
if (nextWord > -1)
|
|
{
|
|
// ready for next word
|
|
bits = (pos > 31) ? 32 : pos;
|
|
wshift = (pos > 31) ? 0 : 32-bits;
|
|
resultMantissa <<= bits;
|
|
}
|
|
else
|
|
{
|
|
break; // not enough data for full 53 bits
|
|
}
|
|
}
|
|
}
|
|
|
|
// rounding
|
|
if (pos > 0)
|
|
{
|
|
; // insufficient data for rounding
|
|
}
|
|
else
|
|
{
|
|
bit53 = ( resultMantissa & 0x1 ) ? true : false;
|
|
if (bits == 32)
|
|
{
|
|
// last extract was exactly 32 bits, so rest of bits are in next word if there is one
|
|
if (nextWord > -1)
|
|
{
|
|
w = wordBuffer[nextWord--];
|
|
bit54 = ( w & (ONEL<<31) ) ? true : false;
|
|
rest = ( w & ((ONEL<<31)-1) ) ? true : false;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// we know bit54 is in this word but the rest of the data may be in the next
|
|
AvmAssert(bits < 32 && wshift > 0);
|
|
bit54 = ( w & (ONEL<<(wshift-1)) ) ? true : false;
|
|
|
|
if (wshift > 1)
|
|
rest = ( w & ((ONEL<<(wshift-1))-1) ) ? true : false;
|
|
|
|
// pick up any residual bits
|
|
if (nextWord > -1)
|
|
rest = rest || (wordBuffer[nextWord--] != 0);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* ieee rounding is to nearest even value (bit54 is 2^-1)
|
|
* x...1 1.. -> round up since odd (but53 set)
|
|
* x...0 1...1.. -> round up since value > 1/2
|
|
*/
|
|
if (bit54 && (bit53 || rest))
|
|
resultMantissa += 1;
|
|
|
|
double result=0;
|
|
int32 expBase2 = lg2() + 1 - 53; // if negative, then we've already captured all the data in the mantissaResult and we can ignore.
|
|
result = (double)resultMantissa;
|
|
if (expBase2 > 0)
|
|
{
|
|
if (expBase2 < 64)
|
|
{
|
|
uint64 uint64_1 = 1;
|
|
result *= (double)(uint64_1 << expBase2);
|
|
}
|
|
else
|
|
{
|
|
result *= MathUtils::pow(2,expBase2);
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
// Compare this vs other, return -1 if this < other, 0 if this == other, or 1 if this > other.
|
|
// (todo: optimization for D2A would be to check if comparison was larger than an argument value
|
|
// currently, we add the argument to this and compare the result with other).
|
|
int32 BigInteger::compare(const BigInteger *other) const
|
|
{
|
|
// if a is bigger than other, subtract has to be positive (assuming unsigned value)
|
|
int result = 0;
|
|
if (numWords > other->numWords)
|
|
result = 1;
|
|
else if (numWords < other->numWords)
|
|
result = -1;
|
|
else
|
|
{
|
|
// otherwise, they are they same number of uint32 words. need to check numWords by numWords
|
|
for(int x = numWords-1; x > -1 ; x--)
|
|
{
|
|
if (wordBuffer[x] != other->wordBuffer[x])
|
|
{
|
|
result = (wordBuffer[x] < other->wordBuffer[x]) ? -1 : 1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
return result;
|
|
}
|
|
|
|
// Multiply by an integer factor and add an integer increment. The addition is essentially free,
|
|
// use this with a zero second argument for basic multiplication.
|
|
void BigInteger::multAndIncrementBy(int32 factor, int32 addition)
|
|
{
|
|
uint64 opResult;
|
|
|
|
// perform mult op, moving carry forward.
|
|
uint64 carry = addition; // init cary with first addition
|
|
int x;
|
|
for(x=0; x < numWords; x++)
|
|
{
|
|
opResult = (uint64)wordBuffer[x] * (uint64)factor + carry;
|
|
carry = opResult >> 32;
|
|
wordBuffer[x] = (uint32)(opResult & 0xffffffff);
|
|
}
|
|
|
|
// if carry goes over the existing top, may need to expand wordBuffer
|
|
if (carry)
|
|
{
|
|
setNumWords(numWords+1);
|
|
wordBuffer[x] = (uint32)carry;
|
|
}
|
|
|
|
}
|
|
|
|
// Multiply by another BigInteger. If optional arg result is not null, reuse it for
|
|
// result, else allocate a new result.
|
|
// (note, despite the name "smallerNum", argument does not need to be smaller than this).
|
|
BigInteger* BigInteger::mult(const BigInteger* smallerNum, BigInteger* result) const
|
|
{
|
|
// Need to know which is the bigger number in terms of number of words.
|
|
const BigInteger *biggerNum = this;
|
|
if (biggerNum->numWords < smallerNum->numWords)
|
|
{
|
|
const BigInteger *temp = biggerNum;
|
|
biggerNum = smallerNum;
|
|
smallerNum = temp;
|
|
}
|
|
|
|
// Make sure result is big enough, initialize with zeros
|
|
int maxNewNumWords = biggerNum->numWords + smallerNum->numWords;
|
|
result->setNumWords(maxNewNumWords); // we'll trim the excess at the end.
|
|
|
|
// wipe entire buffer (initToZero flag in setNumWords only sets new elements to zero)
|
|
for(int x = 0; x < maxNewNumWords; x++)
|
|
result->wordBuffer[x] = 0;
|
|
|
|
// do the math like gradeschool. To optimize, use an FFT (http://numbers.computation.free.fr/Constants/Algorithms/fft.html)
|
|
for(int x = 0; x < smallerNum->numWords; x++)
|
|
{
|
|
uint64 factor = (uint64) smallerNum->wordBuffer[x];
|
|
if (factor) // if 0, nothing to do.
|
|
{
|
|
uint32* pResult = result->wordBuffer+x; // each pass we rewrite elements of result offset by the pass iteration
|
|
uint64 product;
|
|
uint64 carry = 0;
|
|
|
|
for(int y = 0; y < biggerNum->numWords; y++)
|
|
{
|
|
product = (biggerNum->wordBuffer[y] * factor) + *pResult + carry;
|
|
carry = product >> 32;
|
|
*pResult++ = (uint32)(product & 0xffffffff);
|
|
}
|
|
*pResult = (uint32)carry;
|
|
}
|
|
}
|
|
|
|
// remove leading zeros
|
|
result->trimLeadingZeros();
|
|
|
|
return result;
|
|
}
|
|
|
|
// Divide this by divisor, put the remainder (i.e. this % divisor) into residual. If optional third argument result
|
|
// is not null, use it to store the result of the div, else allocate a new BigInteger for the result.
|
|
// Note: this has been hard to get right. If bugs do show up, use divideByReciprocalMethod instead
|
|
// Note2: this is optimized for the types of numerator/denominators generated by D2A. It will not work when
|
|
// the result would be a value bigger than 9. For general purpose BigInteger division, use divideByReciprocalMethod.
|
|
BigInteger* BigInteger::quickDivMod(const BigInteger* divisor, BigInteger* residual, BigInteger* result)
|
|
{
|
|
// handle easy cases where divisor is >= this
|
|
int compareTo = this->compare(divisor);
|
|
if (compareTo == -1)
|
|
{
|
|
residual->copyFrom(this);
|
|
result->setValue(0);
|
|
return result;
|
|
}
|
|
else if (compareTo == 0)
|
|
{
|
|
residual->setValue(0);
|
|
result->setValue(1);
|
|
return result;
|
|
}
|
|
|
|
int dWords = divisor->numWords;
|
|
/* this section only necessary for true division instead of special case division needed by D2A. We are
|
|
assuming the result is a single digit value < 10 and > -1
|
|
int next = this->numWords - dWords;
|
|
residual->copyFrom(this, next, dWords); // residual holds a divisor->numWords sized chunk of this.
|
|
*/
|
|
residual->copyFrom(this,0,numWords);
|
|
BigInteger decrement;
|
|
decrement.setFromInteger(0);
|
|
result->setNumWords(divisor->numWords, true);
|
|
uint64 factor;
|
|
|
|
//do // need to loop over dword chunks of residual to make this handle division of any arbitrary bigIntegers
|
|
{
|
|
// guess largest factor that * divisor will fit into residual
|
|
factor = (uint64)(residual->wordBuffer[residual->numWords-1]) / divisor->wordBuffer[dWords-1];
|
|
if ( ((factor <= 0) || (factor > 10)) // over estimate of 9 could be 10
|
|
&& residual->numWords > 1 && dWords > 1)
|
|
{
|
|
uint64 bigR = ( ((uint64)residual->wordBuffer[residual->numWords-1]) << 32)
|
|
+ (residual->wordBuffer[residual->numWords-2]);
|
|
factor = bigR / divisor->wordBuffer[dWords-1];
|
|
if (factor > 9)
|
|
{ // Note: This only works because of the relative size of the two operands
|
|
// which the D2A class produces. todo: try generating a numerator out of the
|
|
// the top 32 significant bits of residual (may have to get bits from two seperate words)
|
|
// and a denominator out of the top 24 significant bits of divisor and use them for
|
|
// the factor guess. Same principal as above applied to 8 bit units.
|
|
factor = 9;
|
|
/*
|
|
BigInteger::free(decrement);
|
|
return divideByReciprocalMethod(divisor, residual, result);
|
|
*/
|
|
}
|
|
}
|
|
if (factor)
|
|
{
|
|
decrement.copyFrom(divisor);
|
|
decrement.multAndIncrementBy( (uint32)factor,0);
|
|
// check for overestimate
|
|
// fix bug 121952: must check for larger overestimate, which
|
|
// can occur despite the checks above in some rare cases.
|
|
// To see this case, use:
|
|
// this=4398046146304000200000000
|
|
// divisor=439804651110400000000000
|
|
while (decrement.compare(residual) == 1 && factor > 0)
|
|
{
|
|
decrement.decrementBy(divisor);
|
|
factor--;
|
|
}
|
|
|
|
// reduce dividend (aka residual) by factor*divisor, leave remainder in residual
|
|
residual->decrementBy(&decrement);
|
|
}
|
|
|
|
// check for factor 0 underestimate
|
|
int comparedTo = residual->compare(divisor);
|
|
if (comparedTo == 1) // correct guess if its an off by one estimate
|
|
{
|
|
residual->decrementBy(divisor);
|
|
factor++;
|
|
}
|
|
|
|
result->wordBuffer[0] = (uint32)factor;
|
|
|
|
/* The above works for the division requirements of D2A, where divisor is always around 10 larger
|
|
than the dividend and the result is always a digit 1-9.
|
|
To make this routine work for general division, the following would need to be fleshed out /debugged.
|
|
residual->trimLeadingZeros();
|
|
|
|
// While we have more words to divide by and the residual has less words than the
|
|
// divisor,
|
|
if (--next >= 0)
|
|
{
|
|
do
|
|
{
|
|
result->lshiftBy(32); // shift current result over by a word
|
|
residual->lshiftBy(32);// shift remainder over by a word
|
|
residual->wordBuffer[0] = this->wordBuffer[next]; // drop next word of "this" into bottom word of remainder
|
|
}
|
|
while(residual->numWords < dWords);
|
|
}
|
|
|
|
} while(next >= 0);
|
|
*/
|
|
}
|
|
|
|
// trim zeros off top of residual
|
|
result->trimLeadingZeros();
|
|
return result;
|
|
}
|
|
|
|
/* Was hoping dividing via a Newton's approximation of the reciprocal would be faster, but
|
|
its not (makes D2A about twice as slow!). Its not the 32bit divide above that's slow,
|
|
its how many times you have to iterate over entire BigIntegers. Below uses a shift,
|
|
and three multiplies:
|
|
*/
|
|
BigInteger* BigInteger::divideByReciprocalMethod(const BigInteger* divisor, BigInteger* residual, BigInteger* result)
|
|
{
|
|
// handle easy cases where divisor is >= this
|
|
int compareTo = this->compare(divisor);
|
|
if (compareTo == -1)
|
|
{
|
|
residual->copyFrom(this);
|
|
result->setValue(0);
|
|
return result;
|
|
}
|
|
else if (compareTo == 0)
|
|
{
|
|
residual->setValue(0);
|
|
result->setValue(1);
|
|
return result;
|
|
}
|
|
|
|
uint32 d2Prec = divisor->lg2();
|
|
uint32 e = 1 + d2Prec;
|
|
uint32 ag = 1;
|
|
uint32 ar = 31 + this->lg2() - d2Prec;
|
|
BigInteger u;
|
|
u.setFromInteger(1);
|
|
|
|
BigInteger ush;
|
|
ush.setFromInteger(1);
|
|
|
|
BigInteger usq;
|
|
usq.setFromInteger(0);
|
|
|
|
while (1)
|
|
{
|
|
u.lshift(e + 1,&ush);
|
|
divisor->mult(&u,&usq); // usq = divisor*u^2
|
|
usq.multBy(&u);
|
|
ush.subtract(&usq, &u); // u = ush - usq;
|
|
|
|
int32 ush2 = u.lg2(); // ilg2(u);
|
|
e *= 2;
|
|
ag *= 2;
|
|
int32 usq2 = 4 + ag;
|
|
ush2 -= usq2; // BigInteger* diff = ush->subtract(usq); // ush -= usq; ush > 0
|
|
if (ush2 > 0) // (ush->compare(usq) == 1)
|
|
{
|
|
u.rshiftBy(ush2); // u >>= ush;
|
|
e -= ush2;
|
|
}
|
|
if (ag > ar)
|
|
break;
|
|
}
|
|
result = this->mult(&u,result); // mult by reciprocal (scaled by e)
|
|
result->rshiftBy(e); // remove scaling
|
|
|
|
BigInteger temp;
|
|
temp.setFromInteger(0);
|
|
divisor->mult(result, &temp); // compute residual as this - divisor*result
|
|
this->subtract(&temp,residual); // todo: should be a more optimal way of doing this
|
|
|
|
// ... doesn't work, e is the wrong scale for this (too large)....
|
|
// residual = this->lshift(e,residual); // residual = (this*2^e - result) / 2^e
|
|
// residual->decrementBy(result);
|
|
// residual->rshiftBy(e); // remove scaling
|
|
return(result);
|
|
}
|
|
|
|
// q = this->divBy(divisor) is equilvalent to: q = this->quickDivMod(divisor,remainderResult); this = remainderResult;
|
|
BigInteger* BigInteger::divBy(const BigInteger* divisor, BigInteger* divResult)
|
|
{
|
|
BigInteger tempInt;
|
|
tempInt.setFromInteger(0);
|
|
|
|
quickDivMod(divisor, &tempInt, divResult); // this has been hard to get right. If bugs do show up,
|
|
//divResult = divideByReciprocalMethod(divisor,tempInt,divResult); // try this version instead Its slower, but less likely to be buggy
|
|
this->copyFrom(&tempInt);
|
|
return divResult;
|
|
}
|
|
|
|
uint32 BigInteger::lg2() const
|
|
{
|
|
uint32 powersOf2 = (numWords-1)*32;
|
|
for(uint32 topWord = wordBuffer[numWords-1]; topWord > 1; topWord >>= 1)
|
|
powersOf2++;
|
|
return powersOf2;
|
|
}
|
|
|
|
|
|
// Shift a BigInteger by <shiftBy> bits to left. If
|
|
// result is not NULL, write result into it, else allocate a new BigInteger.
|
|
BigInteger* BigInteger::lshift(uint32 shiftBy, BigInteger* result) const
|
|
{
|
|
// calculate how much larger the result will be
|
|
int numNewWords = shiftBy >> 5; // i.e. div by 32
|
|
int totalWords = numNewWords + numWords + 1; // overallocate by 1, trim if necessary at end.
|
|
result->setNumWords(totalWords,true);
|
|
|
|
|
|
// make sure we don't create more words for 0
|
|
if ( numWords == 1 && wordBuffer[0] == 0 )
|
|
{
|
|
result->setValue(0); // 0 << num is still 0
|
|
return result;
|
|
}
|
|
const uint32* pSourceBuff = wordBuffer;
|
|
uint32* pResultBuff = result->wordBuffer;
|
|
for(int x = 0; x < numNewWords; x++)
|
|
*pResultBuff++ = 0;
|
|
// move bits from wordBuffer into result's wordBuffer shifted by (shiftBy % 32)
|
|
shiftBy &= 0x1f;
|
|
if (shiftBy) {
|
|
uint32 carry = 0;
|
|
int shiftCarry = 32 - shiftBy;
|
|
for(int x=0; x < numWords; x++)
|
|
{
|
|
*pResultBuff++ = *pSourceBuff << shiftBy | carry;
|
|
carry = *pSourceBuff++ >> shiftCarry;
|
|
}
|
|
*pResultBuff = carry; // final carry may add a word
|
|
if (*pResultBuff)
|
|
++totalWords; // prevent trim of overallocated extra word
|
|
}
|
|
else for(int x=0; x < numWords; x++) // shift was by a clean multiple of 32, just move words
|
|
{
|
|
*pResultBuff++ = *pSourceBuff++;
|
|
}
|
|
result->numWords = totalWords - 1; // trim over allocated extra word
|
|
return result;
|
|
}
|
|
|
|
// Shift a BigInteger by <shiftBy> bits to right. If
|
|
// result is not NULL, write result into it, else allocate a new BigInteger.
|
|
// (todo: might be possible to combine rshift and lshift into a single function
|
|
// with argument specifying which direction to shift, but result might be messy/harder to get right)
|
|
BigInteger* BigInteger::rshift(uint32 shiftBy, BigInteger* result) const
|
|
{
|
|
int numRemovedWords = shiftBy >> 5; // i.e. div by 32
|
|
|
|
// calculate how much larger the result will be
|
|
int totalWords = numWords - numRemovedWords;
|
|
result->setNumWords(totalWords,true);
|
|
|
|
// check for underflow
|
|
if (numRemovedWords > numWords)
|
|
{
|
|
result->setValue(0);
|
|
return result;
|
|
}
|
|
|
|
// move bits from wordBuffer into result's wordBuffer shifted by (shiftBy % 32)
|
|
uint32* pResultBuff = &(result->wordBuffer[totalWords-1]);
|
|
const uint32* pSourceBuff = &(wordBuffer[numWords-1]);
|
|
shiftBy &= 0x1f;
|
|
if (shiftBy)
|
|
{
|
|
int shiftCarry = 32 - shiftBy;
|
|
uint32 carry = 0;
|
|
|
|
for(int x=totalWords-1; x > -1; x--)
|
|
{
|
|
*pResultBuff-- = *pSourceBuff >> shiftBy | carry;
|
|
carry = *pSourceBuff-- << shiftCarry;
|
|
}
|
|
}
|
|
else for(int x=totalWords-1; x > -1; x--) // shift was by a clean multiple of 32, just move words
|
|
{
|
|
*pResultBuff-- = *pSourceBuff--;
|
|
}
|
|
result->numWords = totalWords;
|
|
result->trimLeadingZeros(); // shrink numWords down to correct value
|
|
return result;
|
|
}
|
|
|
|
// Add or subtract two BigIntegers. If subtract, we assume the argument is smaller than this since we
|
|
// don't support negative numbers. If optional third argument result is not null, reuse it for result
|
|
// else allocate a new BigInteger for the result.
|
|
BigInteger *BigInteger::addOrSubtract(const BigInteger* smallerNum, bool isAdd, BigInteger* result) const
|
|
{
|
|
// figure out which operand is the biggest in terms of number of words.
|
|
int comparedTo = compare(smallerNum);
|
|
const BigInteger* biggerNum = this;
|
|
if (comparedTo < 0)
|
|
{
|
|
const BigInteger* temp = biggerNum;
|
|
biggerNum = smallerNum;
|
|
smallerNum = temp;
|
|
AvmAssert(isAdd || comparedTo >= 0); // the d2a/a2d code should never subtract a larger from a smaller.
|
|
// all of the BigInteger code assumes positive numbers. Proper
|
|
// handling would be to create a negative result here (and check for
|
|
// negative results everywhere).
|
|
}
|
|
|
|
result->setNumWords(biggerNum->numWords+1, true);
|
|
|
|
if (!isAdd && !comparedTo) // i.e. this - smallerNum == 0
|
|
{
|
|
result->setValue(0);
|
|
return result;
|
|
}
|
|
|
|
// do the math: loop over common words of both numbers, performing - or + and carrying the
|
|
// overflow/borrow forward to next word.
|
|
uint64 borrow = 0;
|
|
uint64 x;
|
|
int index;
|
|
for( index = 0; index < smallerNum->numWords; index++)
|
|
{
|
|
if (isAdd)
|
|
x = ((uint64)biggerNum->wordBuffer[index]) + smallerNum->wordBuffer[index] + borrow;
|
|
else
|
|
x = ((uint64)biggerNum->wordBuffer[index]) - smallerNum->wordBuffer[index] - borrow; // note x is unsigned. Ok even if result would be negative however
|
|
borrow = x >> 32 & (uint32)1;
|
|
result->wordBuffer[index] = (uint32)(x & 0xffffffff);
|
|
}
|
|
|
|
// loop over remaining words of the larger number, carying borrow/overflow forward
|
|
for( ; index < biggerNum->numWords; index++)
|
|
{
|
|
if (isAdd)
|
|
x = ((uint64)biggerNum->wordBuffer[index]) + borrow;
|
|
else
|
|
x = ((uint64)biggerNum->wordBuffer[index]) - borrow;
|
|
borrow = x >> 32 & (uint32)1;
|
|
result->wordBuffer[index] = (uint32)(x & 0xffffffff);
|
|
}
|
|
|
|
// handle final overflow if this is add
|
|
if (isAdd && borrow)
|
|
{
|
|
result->wordBuffer[index] = (uint32)(borrow & 0xffffffff);
|
|
index++;
|
|
}
|
|
// loop backwards over result, removing leading zeros from our numWords count
|
|
while( !(result->wordBuffer[--index]) )
|
|
{
|
|
}
|
|
result->numWords = index+1;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
}
|