private void Mul(ref BigNumber numOp) {
Debug.Assert(0 != (this.u2 & 0x80000000));
Debug.Assert(0 != (numOp.u2 & 0x80000000));
//uint *rgu = stackalloc uint[6];
uint rgu0 = 0, rgu1 = 0, rgu2 = 0, rgu3 = 0, rgu4 = 0, rgu5 = 0;
uint uLo, uHi, uT;
uint wCarry;
if (0 != (uT = this.u0)) {
uLo = MulU(uT, numOp.u0, out uHi);
rgu0 = uLo;
rgu1 = uHi;
uLo = MulU(uT, numOp.u1, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu1, uLo);
AddU(ref rgu2, uHi + wCarry);
uLo = MulU(uT, numOp.u2, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu2, uLo);
AddU(ref rgu3, uHi + wCarry);
}
if (0 != (uT = this.u1)) {
uLo = MulU(uT, numOp.u0, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu1, uLo);
wCarry = AddU(ref rgu2, uHi + wCarry);
if (0 != wCarry && 0 != AddU(ref rgu3, 1)) {
AddU(ref rgu4, 1);
}
uLo = MulU(uT, numOp.u1, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu2, uLo);
wCarry = AddU(ref rgu3, uHi + wCarry);
if (0 != wCarry) {
AddU(ref rgu4, 1);
}
uLo = MulU(uT, numOp.u2, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu3, uLo);
AddU(ref rgu4, uHi + wCarry);
}
uT = this.u2;
Debug.Assert(0 != uT);
uLo = MulU(uT, numOp.u0, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu2, uLo);
wCarry = AddU(ref rgu3, uHi + wCarry);
if (0 != wCarry && 0 != AddU(ref rgu4, 1)) {
AddU(ref rgu5, 1);
}
uLo = MulU(uT, numOp.u1, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu3, uLo);
wCarry = AddU(ref rgu4, uHi + wCarry);
if (0 != wCarry) {
AddU(ref rgu5, 1);
}
uLo = MulU(uT, numOp.u2, out uHi);
Debug.Assert(uHi < 0xFFFFFFFF);
wCarry = AddU(ref rgu4, uLo);
AddU(ref rgu5, uHi + wCarry);
// Compute the new exponent
this.exp += numOp.exp;
// Accumulate the error. Adding doesn't necessarily give an accurate
// bound if both of the errors are bigger than 2.
Debug.Assert(this.error <= 2 || numOp.error <= 2);
this.error += numOp.error;
// Handle rounding and normalize.
if (0 == (rgu5 & 0x80000000)) {
if (0 != (rgu2 & 0x40000000) &&
(0 != (rgu2 & 0xBFFFFFFF) || 0 != rgu1 || 0 != rgu0)) {
// Round up by 1
if (0 != AddU(ref rgu2, 0x40000000)
&& 0 != AddU(ref rgu3, 1)
&& 0 != AddU(ref rgu4, 1)
) {
AddU(ref rgu5, 1);
if (0 != (rgu5 & 0x80000000)) {
goto LNormalized;
}
}
}
// have to shift by one
Debug.Assert(0 != (rgu5 & 0x40000000));
this.u2 = (rgu5 << 1) | (rgu4 >> 31);
this.u1 = (rgu4 << 1) | (rgu3 >> 31);
this.u0 = (rgu3 << 1) | (rgu2 >> 31);
this.exp--;
this.error <<= 1;
// Add one for the error.
if (0 != (rgu2 & 0x7FFFFFFF) || 0 != rgu1 || 0 != rgu0) {
this.error++;
}
return;
} else {
if (0 != (rgu2 & 0x80000000) &&
(0 != (rgu3 & 1) || 0 != (rgu2 & 0x7FFFFFFF) ||
0 != rgu1 || 0 != rgu0)) {
// Round up by 1
if (0 != AddU(ref rgu3, 1) && 0 != AddU(ref rgu4, 1) && 0 != AddU(ref rgu5, 1)) {
Debug.Assert(0 == rgu3);
Debug.Assert(0 == rgu4);
Debug.Assert(0 == rgu5);
rgu5 = 0x80000000;
this.exp++;
}
}
}
LNormalized:
this.u2 = rgu5;
this.u1 = rgu4;
this.u0 = rgu3;
// Add one for the error.
if (0 != rgu2 || 0 != rgu1 || 0 != rgu0) {
this.error++;
}
}