// The ShortDivide() algorithm works like dividing a polynomial which // looks like: // (ax3 + bx2 + cx + d) / N = (ax3 + bx2 + cx + d) * (1/N) // The 1/N distributes over the polynomial: // (ax3 * (1/N)) + (bx2 * (1/N)) + (cx * (1/N)) + (d * (1/N)) // (ax3/N) + (bx2/N) + (cx/N) + (d/N) // The algorithm goes from left to right and reduces that polynomial // expression. So it starts with Quotient being a copy of ToDivide // and then it reduces Quotient from left to right. private bool ShortDivide( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { Quotient.Copy( ToDivide ); // DivideBy has an Index of zero: ulong DivideByU = DivideBy.GetD( 0 ); ulong RemainderU = 0; // Get the first one set up. if( DivideByU > Quotient.GetD( Quotient.GetIndex()) ) { Quotient.SetD( Quotient.GetIndex(), 0 ); } else { ulong OneDigit = Quotient.GetD( Quotient.GetIndex() ); Quotient.SetD( Quotient.GetIndex(), OneDigit / DivideByU ); RemainderU = OneDigit % DivideByU; ToDivide.SetD( ToDivide.GetIndex(), RemainderU ); } // Now do the rest. for( int Count = Quotient.GetIndex(); Count >= 1; Count-- ) { ulong TwoDigits = ToDivide.GetD( Count ); TwoDigits <<= 32; TwoDigits |= ToDivide.GetD( Count - 1 ); Quotient.SetD( Count - 1, TwoDigits / DivideByU ); RemainderU = TwoDigits % DivideByU; ToDivide.SetD( Count, 0 ); ToDivide.SetD( Count - 1, RemainderU ); // What's left to divide. } // Set the index for the quotient. // The quotient would have to be at least 1 here, // so it will find where to set the index. for( int Count = Quotient.GetIndex(); Count >= 0; Count-- ) { if( Quotient.GetD( Count ) != 0 ) { Quotient.SetIndex( Count ); break; } } Remainder.SetD( 0, RemainderU ); Remainder.SetIndex( 0 ); if( RemainderU == 0 ) return true; else return false; }
private void LongDivide3( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { int TestIndex = ToDivide.GetIndex() - DivideBy.GetIndex(); if( TestIndex < 0 ) throw( new Exception( "TestIndex < 0 in Divide3." )); if( TestIndex != 0 ) { // Is 1 too high? TestForDivide1.SetDigitAndClear( TestIndex, 1 ); MultiplyTopOne( TestForDivide1, DivideBy ); if( ToDivide.ParamIsGreater( TestForDivide1 )) TestIndex--; } // Keep a copy of the originals. ToDivideKeep.Copy( ToDivide ); DivideByKeep.Copy( DivideBy ); ulong TestBits = DivideBy.GetD( DivideBy.GetIndex()); int ShiftBy = FindShiftBy( TestBits ); ToDivide.ShiftLeft( ShiftBy ); // Multiply the numerator and the denominator DivideBy.ShiftLeft( ShiftBy ); // by the same amount. ulong MaxValue; if( (ToDivide.GetIndex() - 1) > (DivideBy.GetIndex() + TestIndex) ) { MaxValue = ToDivide.GetD( ToDivide.GetIndex()); } else { MaxValue = ToDivide.GetD( ToDivide.GetIndex()) << 32; MaxValue |= ToDivide.GetD( ToDivide.GetIndex() - 1 ); } ulong Denom = DivideBy.GetD( DivideBy.GetIndex()); if( Denom != 0 ) MaxValue = MaxValue / Denom; else MaxValue = 0xFFFFFFFF; if( MaxValue > 0xFFFFFFFF ) MaxValue = 0xFFFFFFFF; if( MaxValue == 0 ) throw( new Exception( "MaxValue is zero at the top in LongDivide3()." )); Quotient.SetDigitAndClear( TestIndex, 1 ); Quotient.SetD( TestIndex, 0 ); TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); Multiply( Test2, DivideBy ); if( !Test2.IsEqual( TestForDivide1 )) throw( new Exception( "In Divide3() !IsEqual( Test2, TestForDivide1 )" )); */ if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchExactCount++; // Most of the time (roughly 5 out of every 6 times) // this MaxValue estimate is exactly right: Quotient.SetD( TestIndex, MaxValue ); } else { // MaxValue can't be zero here. If it was it would // already be low enough before it got here. MaxValue--; if( MaxValue == 0 ) throw( new Exception( "After decrement: MaxValue is zero in LongDivide3()." )); TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); MultiplyTop( TestForDivide1, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, MaxValue ); Multiply( Test2, DivideBy ); if( !Test2.IsEqual( Test1 )) throw( new Exception( "Top one. !Test2.IsEqual( Test1 ) in LongDivide3()" )); */ if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchDecCount++; Quotient.SetD( TestIndex, MaxValue ); } else { // TestDivideBits is done as a last resort, but it's rare. // But it does at least limit it to a worst case scenario // of trying 32 bits, rather than 4 billion or so decrements. TestDivideBits( MaxValue, true, TestIndex, ToDivide, DivideBy, Quotient, Remainder ); } // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; // HighestToMatchGap: 4,294,967,293 // uint size: 4,294,967,295 uint } // If it's done. if( TestIndex == 0 ) { TestForDivide1.Copy( Quotient ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); Subtract( Remainder, TestForDivide1 ); //if( DivideByKeep.ParamIsGreater( Remainder )) // throw( new Exception( "Remainder > DivideBy in LongDivide3()." )); return; } // Now do the rest of the digits. TestIndex--; while( true ) { TestForDivide1.Copy( Quotient ); // First Multiply() for each digit. Multiply( TestForDivide1, DivideBy ); // if( ToDivide.ParamIsGreater( TestForDivide1 )) // throw( new Exception( "Bug here in LongDivide3()." )); Remainder.Copy( ToDivide ); Subtract( Remainder, TestForDivide1 ); MaxValue = Remainder.GetD( Remainder.GetIndex()) << 32; int CheckIndex = Remainder.GetIndex() - 1; if( CheckIndex > 0 ) MaxValue |= Remainder.GetD( CheckIndex ); Denom = DivideBy.GetD( DivideBy.GetIndex()); if( Denom != 0 ) MaxValue = MaxValue / Denom; else MaxValue = 0xFFFFFFFF; if( MaxValue > 0xFFFFFFFF ) MaxValue = 0xFFFFFFFF; TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); // There's a minimum of two full Multiply() operations per digit. Multiply( TestForDivide1, DivideBy ); if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // Most of the time this MaxValue estimate is exactly right: // ToMatchExactCount++; Quotient.SetD( TestIndex, MaxValue ); } else { MaxValue--; TestForDivide1.Copy( Quotient ); TestForDivide1.SetD( TestIndex, MaxValue ); Multiply( TestForDivide1, DivideBy ); if( TestForDivide1.ParamIsGreaterOrEq( ToDivide )) { // ToMatchDecCount++; Quotient.SetD( TestIndex, MaxValue ); } else { TestDivideBits( MaxValue, false, TestIndex, ToDivide, DivideBy, Quotient, Remainder ); // TestGap = MaxValue - LgQuotient.D[TestIndex]; // if( TestGap > HighestToMatchGap ) // HighestToMatchGap = TestGap; } } if( TestIndex == 0 ) break; TestIndex--; } TestForDivide1.Copy( Quotient ); Multiply( TestForDivide1, DivideByKeep ); Remainder.Copy( ToDivideKeep ); Subtract( Remainder, TestForDivide1 ); // if( DivideByKeep.ParamIsGreater( Remainder )) // throw( new Exception( "Remainder > DivideBy in LongDivide3()." )); }
private void SearchSqrtXPart( int TestIndex, Integer Square, Integer SqrRoot ) { // B is the Big part of the number that has already been found. // S = (B + x)^2 // S = B^2 + 2Bx + x^2 // S - B^2 = 2Bx + x^2 // R = S - B^2 // R = 2Bx + x^2 // R = x(2B + x) SqrtXPartTest1.Copy( SqrRoot ); // B DoSquare( SqrtXPartTest1 ); // B^2 SqrtXPartDiff.Copy( Square ); Subtract( SqrtXPartDiff, SqrtXPartTest1 ); // S - B^2 SqrtXPartTwoB.Copy( SqrRoot ); // B SqrtXPartTwoB.ShiftLeft( 1 ); // Times 2 for 2B. SqrtXPartTest1.Copy( SqrtXPartTwoB ); ulong TestBits = SqrtXPartTest1.GetD( SqrtXPartTest1.GetIndex()); int ShiftBy = FindShiftBy( TestBits ); SqrtXPartR2.Copy( SqrtXPartDiff ); SqrtXPartR2.ShiftLeft( ShiftBy ); // Multiply the numerator and the denominator SqrtXPartTest1.ShiftLeft( ShiftBy ); // by the same amount. ulong Highest; if( SqrtXPartR2.GetIndex() == 0 ) { Highest = SqrtXPartR2.GetD( SqrtXPartR2.GetIndex()); } else { Highest = SqrtXPartR2.GetD( SqrtXPartR2.GetIndex()) << 32; Highest |= SqrtXPartR2.GetD( SqrtXPartR2.GetIndex() - 1 ); } ulong Denom = SqrtXPartTest1.GetD( SqrtXPartTest1.GetIndex()); if( Denom == 0 ) Highest = 0xFFFFFFFF; else Highest = Highest / Denom; if( Highest == 0 ) { SqrRoot.SetD( TestIndex, 0 ); return; } if( Highest > 0xFFFFFFFF ) Highest = 0xFFFFFFFF; uint BitTest = 0x80000000; ulong XDigit = 0; ulong TempXDigit = 0; for( int BitCount = 0; BitCount < 32; BitCount++ ) { TempXDigit = XDigit | BitTest; if( TempXDigit > Highest ) { BitTest >>= 1; continue; } SqrtXPartTest1.Copy( SqrtXPartTwoB ); SqrtXPartTest1.SetD( TestIndex, TempXDigit ); // 2B + x SqrtXPartTest2.SetDigitAndClear( TestIndex, TempXDigit ); // Set X. MultiplyTop( SqrtXPartTest2, SqrtXPartTest1 ); if( SqrtXPartTest2.ParamIsGreaterOrEq( SqrtXPartDiff )) XDigit |= BitTest; // Then keep the bit. BitTest >>= 1; } SqrRoot.SetD( TestIndex, XDigit ); }
internal void SubtractULong( Integer Result, ulong ToSub ) { if( Result.IsULong()) { ulong ResultU = Result.GetAsULong(); if( ToSub > ResultU ) throw( new Exception( "SubULong() (IsULong() and (ToSub > Result)." )); ResultU = ResultU - ToSub; Result.SetD( 0, ResultU & 0xFFFFFFFF ); Result.SetD( 1, ResultU >> 32 ); if( Result.GetD( 1 ) == 0 ) Result.SetIndex( 0 ); else Result.SetIndex( 1 ); return; } // If it got this far then Index is at least 2. SignedD[0] = (long)Result.GetD( 0 ) - (long)(ToSub & 0xFFFFFFFF); SignedD[1] = (long)Result.GetD( 1 ) - (long)(ToSub >> 32); if( (SignedD[0] >= 0) && (SignedD[1] >= 0) ) { // No need to reorganize it. Result.SetD( 0, (ulong)SignedD[0] ); Result.SetD( 1, (ulong)SignedD[1] ); return; } for( int Count = 2; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); Count++ ) { if( SignedD[Count] < 0 ) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if( SignedD[Result.GetIndex()] < 0 ) throw( new Exception( "SubULong() SignedD[Index] < 0." )); for( int Count = 0; Count <= Result.GetIndex(); Count++ ) Result.SetD( Count, (ulong)SignedD[Count] ); for( int Count = Result.GetIndex(); Count >= 0; Count-- ) { if( Result.GetD( Count ) != 0 ) { Result.SetIndex( Count ); return; } } // If this was zero it wouldn't find a nonzero // digit to set the Index to and it would end up down here. Result.SetIndex( 0 ); }
// Finding the square root of a number is similar to division since // it is a search algorithm. The TestSqrtBits method shown next is // very much like TestDivideBits(). It works the same as // FindULSqrRoot(), but on a bigger scale. /* private void TestSqrtBits( int TestIndex, Integer Square, Integer SqrRoot ) { Integer Test1 = new Integer(); uint BitTest = 0x80000000; for( int BitCount = 31; BitCount >= 0; BitCount-- ) { Test1.Copy( SqrRoot ); Test1.D[TestIndex] |= BitTest; Test1.Square(); if( !Square.ParamIsGreater( Test1 ) ) SqrRoot.D[TestIndex] |= BitTest; // Use the bit. BitTest >>= 1; } } */ // In the SquareRoot() method SqrRoot.Index is half of Square.Index. // Compare this to the Square() method where the Carry might or // might not increment the index to an odd number. (So if the Index // was 5 its square root would have an Index of 5 / 2 = 2.) // The SquareRoot1() method uses FindULSqrRoot() either to find the // whole answer, if it's a small number, or it uses it to find the // top part. Then from there it goes on to a bit by bit search // with TestSqrtBits(). public bool SquareRoot( Integer Square, Integer SqrRoot ) { ulong ToMatch; if( Square.IsULong() ) { ToMatch = Square.GetAsULong(); SqrRoot.SetD( 0, FindULSqrRoot( ToMatch )); SqrRoot.SetIndex( 0 ); if( (SqrRoot.GetD(0 ) * SqrRoot.GetD( 0 )) == ToMatch ) return true; else return false; } int TestIndex = Square.GetIndex() >> 1; // LgSquare.Index / 2; SqrRoot.SetDigitAndClear( TestIndex, 1 ); // if( (TestIndex * 2) > (LgSquare.Index - 1) ) if( (TestIndex << 1) > (Square.GetIndex() - 1) ) { ToMatch = Square.GetD( Square.GetIndex()); } else { // LgSquare.Index is at least 2 here. ToMatch = Square.GetD( Square.GetIndex()) << 32; ToMatch |= Square.GetD( Square.GetIndex() - 1 ); } SqrRoot.SetD( TestIndex, FindULSqrRoot( ToMatch )); TestIndex--; while( true ) { // TestSqrtBits( TestIndex, LgSquare, LgSqrRoot ); SearchSqrtXPart( TestIndex, Square, SqrRoot ); if( TestIndex == 0 ) break; TestIndex--; } // Avoid squaring the whole thing to see if it's an exact square root: if( ((SqrRoot.GetD( 0 ) * SqrRoot.GetD( 0 )) & 0xFFFFFFFF) != Square.GetD( 0 )) return false; TestForSquareRoot.Copy( SqrRoot ); DoSquare( TestForSquareRoot ); if( Square.IsEqual( TestForSquareRoot )) return true; else return false; }
private void AddUpAccumulateArray( Integer Result, int HowManyToAdd, int BiggestIndex ) { try { for( int Count = 0; Count <= (BiggestIndex + 1); Count++ ) Result.SetD( Count, 0 ); Result.SetIndex( BiggestIndex ); for( int Count = 0; Count < HowManyToAdd; Count++ ) { int HowManyDigits = AccumulateArray[Count].GetIndex() + 1; for( int CountDigits = 0; CountDigits < HowManyDigits; CountDigits++ ) { ulong Sum = AccumulateArray[Count].GetD( CountDigits ) + Result.GetD( CountDigits ); Result.SetD( CountDigits, Sum ); } } // This is like ax + by + cz + ... = Result. // You know what a, b, c... are. // But you don't know what x, y, and z are. // So how do you reverse this and get x, y and z? // Is this reversible? Result.OrganizeDigits(); } catch( Exception Except ) { throw( new Exception( "Exception in AddUpAccumulateArray(): " + Except.Message )); } }
internal void SubtractPositive( Integer Result, Integer ToSub ) { if( ToSub.IsULong() ) { SubtractULong( Result, ToSub.GetAsULong()); return; } if( ToSub.GetIndex() > Result.GetIndex() ) throw( new Exception( "In Subtract() ToSub.Index > Index." )); for( int Count = 0; Count <= ToSub.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ) - (long)ToSub.GetD( Count ); for( int Count = ToSub.GetIndex() + 1; Count <= Result.GetIndex(); Count++ ) SignedD[Count] = (long)Result.GetD( Count ); for( int Count = 0; Count < Result.GetIndex(); Count++ ) { if( SignedD[Count] < 0 ) { SignedD[Count] += (long)0xFFFFFFFF + 1; SignedD[Count + 1]--; } } if( SignedD[Result.GetIndex()] < 0 ) throw( new Exception( "Subtract() SignedD[Index] < 0." )); for( int Count = 0; Count <= Result.GetIndex(); Count++ ) Result.SetD( Count, (ulong)SignedD[Count] ); for( int Count = Result.GetIndex(); Count >= 0; Count-- ) { if( Result.GetD( Count ) != 0 ) { Result.SetIndex( Count ); return; } } // If it never found a non-zero digit it would get down to here. Result.SetIndex( 0 ); }
internal int MultiplyUIntFromCopy( Integer Result, Integer FromCopy, ulong ToMul ) { int FromCopyIndex = FromCopy.GetIndex(); // The compiler knows that FromCopyIndex doesn't change here so // it can do its range checking on the for-loop before it starts. Result.SetIndex( FromCopyIndex ); for( int Column = 0; Column <= FromCopyIndex; Column++ ) Scratch[Column] = ToMul * FromCopy.GetD( Column ); // Add these up with a carry. Result.SetD( 0, Scratch[0] & 0xFFFFFFFF ); ulong Carry = Scratch[0] >> 32; for( int Column = 1; Column <= FromCopyIndex; Column++ ) { ulong Total = Scratch[Column] + Carry; Result.SetD( Column, Total & 0xFFFFFFFF ); Carry = Total >> 32; } if( Carry != 0 ) { Result.IncrementIndex(); // This might throw an exception if it overflows. Result.SetD( FromCopyIndex + 1, Carry ); } return Result.GetIndex(); }
internal void MultiplyULong( Integer Result, ulong ToMul ) { // Using compile-time checks, this one overflows: // const ulong Test = ((ulong)0xFFFFFFFF + 1) * ((ulong)0xFFFFFFFF + 1); // This one doesn't: // const ulong Test = (ulong)0xFFFFFFFF * ((ulong)0xFFFFFFFF + 1); if( Result.IsZero()) return; // Then the answer is zero, which it already is. if( ToMul == 0 ) { Result.SetToZero(); return; } ulong B0 = ToMul & 0xFFFFFFFF; ulong B1 = ToMul >> 32; if( B1 == 0 ) { MultiplyUInt( Result, (uint)B0 ); return; } // Since B1 is not zero: if( (Result.GetIndex() + 1) >= Integer.DigitArraySize ) throw( new Exception( "Overflow in MultiplyULong." )); for( int Column = 0; Column <= Result.GetIndex(); Column++ ) { M[Column, 0] = B0 * Result.GetD( Column ); // Column + 1 and Row is 1, so it's just like pen and paper. M[Column + 1, 1] = B1 * Result.GetD( Column ); } // Since B1 is not zero, the index is set one higher. Result.IncrementIndex(); // Might throw an exception if it goes out of range. M[Result.GetIndex(), 0] = 0; // Otherwise it would be undefined // when it's added up below. // Add these up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= Result.GetIndex(); Column++ ) { // This does overflow: // const ulong Test = ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)) // + ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)); // Split the ulongs into right and left sides // so that they don't overflow. ulong TotalLeft = 0; ulong TotalRight = 0; // There's only the two rows for this. for( int Row = 0; Row <= 1; Row++ ) { TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } if( Carry != 0 ) { Result.IncrementIndex(); // This can throw an exception. Result.SetD( Result.GetIndex(), Carry ); } }
// This is another optimization. This is used when the top digit // is 1 and all of the other digits are zero. // This is effectively just a shift-left operation. internal void MultiplyTopOne( Integer Result, Integer ToMul ) { // try // { int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTopOne() overflow." )); for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) Result.SetD( Column + Result.GetIndex(), ToMul.GetD( Column )); for( int Column = 0; Column < Result.GetIndex(); Column++ ) Result.SetD( Column, 0 ); // No Carrys need to be done. Result.SetIndex( TotalIndex ); /* } catch( Exception ) // Except ) { // "Bug in MultiplyTopOne: " + Except.Message } */ }
internal void MultiplyUInt( Integer Result, ulong ToMul ) { try { if( ToMul == 0 ) { Result.SetToZero(); return; } if( ToMul == 1 ) return; for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column, 0] = ToMul * Result.GetD( Column ); // Add these up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= Result.GetIndex(); Column++ ) { // Using a compile-time check on this constant, // this Test value does not overflow: // const ulong Test = ((ulong)0xFFFFFFFF * (ulong)(0xFFFFFFFF)) + 0xFFFFFFFF; // ulong Total = checked( M[Column, 0] + Carry ); ulong Total = M[Column, 0] + Carry; Result.SetD( Column, Total & 0xFFFFFFFF ); Carry = Total >> 32; } if( Carry != 0 ) { Result.IncrementIndex(); // This might throw an exception if it overflows. Result.SetD( Result.GetIndex(), Carry ); } } catch( Exception Except ) { throw( new Exception( "Exception in MultiplyUInt(): " + Except.Message )); } }
// This is an optimization for multiplying when only the top digit // of a number has been set and all of the other digits are zero. internal void MultiplyTop( Integer Result, Integer ToMul ) { // try // { int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTop() overflow." )); // Just like Multiply() except that all the other rows are zero: for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) M[Column + Result.GetIndex(), Result.GetIndex()] = Result.GetD( Result.GetIndex() ) * ToMul.GetD( Column ); for( int Column = 0; Column < Result.GetIndex(); Column++ ) Result.SetD( Column, 0 ); ulong Carry = 0; for( int Column = 0; Column <= ToMul.GetIndex(); Column++ ) { ulong Total = M[Column + Result.GetIndex(), Result.GetIndex()] + Carry; Result.SetD( Column + Result.GetIndex(), Total & 0xFFFFFFFF ); Carry = Total >> 32; } Result.SetIndex( TotalIndex ); if( Carry != 0 ) { Result.SetIndex( Result.GetIndex() + 1 ); if( Result.GetIndex() >= Integer.DigitArraySize ) throw( new Exception( "MultiplyTop() overflow." )); Result.SetD( Result.GetIndex(), Carry ); } /* } catch( Exception ) // Except ) { // "Bug in MultiplyTop: " + Except.Message } */ }
// See also: http://en.wikipedia.org/wiki/Karatsuba_algorithm internal void Multiply( Integer Result, Integer ToMul ) { // try // { if( Result.IsZero()) return; if( ToMul.IsULong()) { MultiplyULong( Result, ToMul.GetAsULong()); SetMultiplySign( Result, ToMul ); return; } // It could never get here if ToMul is zero because GetIsULong() // would be true for zero. // if( ToMul.IsZero()) int TotalIndex = Result.GetIndex() + ToMul.GetIndex(); if( TotalIndex >= Integer.DigitArraySize ) throw( new Exception( "Multiply() overflow." )); for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( ToMul.GetD( Row ) == 0 ) { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= Result.GetIndex(); Column++ ) M[Column + Row, Row] = ToMul.GetD( Row ) * Result.GetD( Column ); } } // Add the columns up with a carry. Result.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= TotalIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= ToMul.GetIndex(); Row++ ) { if( Row > Column ) break; if( Column > (Result.GetIndex() + Row) ) continue; // Split the ulongs into right and left sides // so that they don't overflow. TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; Result.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } Result.SetIndex( TotalIndex ); if( Carry != 0 ) { Result.IncrementIndex(); // This can throw an exception if it overflowed the index. Result.SetD( Result.GetIndex(), Carry ); } SetMultiplySign( Result, ToMul ); }
private void DoCRTTest( Integer StartingNumber ) { CRTMath CRTMath1 = new CRTMath( Worker ); ECTime CRTTestTime = new ECTime(); ChineseRemainder CRTTest = new ChineseRemainder( IntMath ); ChineseRemainder CRTTest2 = new ChineseRemainder( IntMath ); ChineseRemainder CRTAccumulate = new ChineseRemainder( IntMath ); ChineseRemainder CRTToTest = new ChineseRemainder( IntMath ); ChineseRemainder CRTTempEqual = new ChineseRemainder( IntMath ); ChineseRemainder CRTTestEqual = new ChineseRemainder( IntMath ); Integer BigBase = new Integer(); Integer ToTest = new Integer(); Integer Accumulate = new Integer(); Integer Test1 = new Integer(); Integer Test2 = new Integer(); CRTTest.SetFromTraditionalInteger( StartingNumber ); // If the digit array size isn't set right in relation to // Integer.DigitArraySize then it can cause an error here. CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( StartingNumber )) throw( new Exception( " !Accumulate.IsEqual( Result )." )); CRTTestEqual.SetFromTraditionalInteger( Accumulate ); if( !CRTMath1.IsEqualToInteger( CRTTestEqual, Accumulate )) throw( new Exception( "IsEqualToInteger() didn't work." )); // Make sure it works with even numbers too. Test1.Copy( StartingNumber ); Test1.SetD( 0, Test1.GetD( 0 ) & 0xFE ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "For even numbers. !Accumulate.IsEqual( Test )." )); //////////// // Make sure the size of this works with the Integer size because // an overflow is hard to find. CRTTestTime.SetToNow(); Test1.SetToMaxValueForCRT(); CRTTest.SetFromTraditionalInteger( Test1 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "For the max value. !Accumulate.IsEqual( Test1 )." )); // Worker.ReportProgress( 0, "CRT Max test seconds: " + CRTTestTime.GetSecondsToNow().ToString( "N1" )); // Worker.ReportProgress( 0, "MaxValue: " + IntMath.ToString10( Accumulate )); // Worker.ReportProgress( 0, "MaxValue.Index: " + Accumulate.GetIndex().ToString()); // Multiplicative Inverse test: Integer TestDivideBy = new Integer(); Integer TestProduct = new Integer(); ChineseRemainder CRTTestDivideBy = new ChineseRemainder( IntMath ); ChineseRemainder CRTTestProduct = new ChineseRemainder( IntMath ); TestDivideBy.Copy( StartingNumber ); TestProduct.Copy( StartingNumber ); IntMath.Multiply( TestProduct, TestDivideBy ); CRTTestDivideBy.SetFromTraditionalInteger( TestDivideBy ); CRTTestProduct.SetFromTraditionalInteger( TestDivideBy ); CRTTestProduct.Multiply( CRTTestDivideBy ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTestProduct ); if( !Accumulate.IsEqual( TestProduct )) throw( new Exception( "Multiply test was bad." )); IntMath.Divide( TestProduct, TestDivideBy, Quotient, Remainder ); if( !Remainder.IsZero()) throw( new Exception( "This test won't work unless it divides it exactly." )); ChineseRemainder CRTTestQuotient = new ChineseRemainder( IntMath ); CRTMath1.MultiplicativeInverse( CRTTestProduct, CRTTestDivideBy, CRTTestQuotient ); // Yes, multiplicative inverse is the same number // as with regular division. Integer TestQuotient = new Integer(); CRTMath1.GetTraditionalInteger( TestQuotient, CRTTestQuotient ); if( !TestQuotient.IsEqual( Quotient )) throw( new Exception( "Modular Inverse in DoCRTTest didn't work." )); // Subtract Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTTest2.SetFromTraditionalInteger( Test2 ); CRTTest.Subtract( CRTTest2 ); IntMath.Subtract( Test1, Test2 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "Subtract test was bad." )); // Add Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); CRTTest.SetFromTraditionalInteger( Test1 ); CRTTest2.SetFromTraditionalInteger( Test2 ); CRTTest.Add( CRTTest2 ); IntMath.Add( Test1, Test2 ); CRTMath1.GetTraditionalInteger( Accumulate, CRTTest ); if( !Accumulate.IsEqual( Test1 )) throw( new Exception( "Add test was bad." )); ///////// CRTBaseMath CBaseMath = new CRTBaseMath( Worker, CRTMath1 ); ChineseRemainder CRTInput = new ChineseRemainder( IntMath ); CRTInput.SetFromTraditionalInteger( StartingNumber ); Test1.Copy( StartingNumber ); IntMath.SetFromString( Test2, "12345678901234567890123456789012345" ); IntMath.Add( Test1, Test2 ); Integer TestModulus = new Integer(); TestModulus.Copy( Test1 ); ChineseRemainder CRTTestModulus = new ChineseRemainder( IntMath ); CRTTestModulus.SetFromTraditionalInteger( TestModulus ); Integer Exponent = new Integer(); Exponent.SetFromULong( PubKeyExponentUint ); CBaseMath.ModularPower( CRTInput, Exponent, CRTTestModulus, false ); IntMath.IntMathNew.ModularPower( StartingNumber, Exponent, TestModulus, false ); if( !CRTMath1.IsEqualToInteger( CRTInput, StartingNumber )) throw( new Exception( "CRTBase ModularPower() didn't work." )); CRTBase ExpTest = new CRTBase( IntMath ); CBaseMath.SetFromCRTNumber( ExpTest, CRTInput ); CBaseMath.GetExponentForm( ExpTest, 37 ); // Worker.ReportProgress( 0, "CRT was good." ); }
/* private bool LongDivide1( Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { Integer Test1 = new Integer(); int TestIndex = ToDivide.Index - DivideBy.Index; if( TestIndex != 0 ) { // Is 1 too high? Test1.SetDigitAndClear( TestIndex, 1 ); Test1.MultiplyTopOne( DivideBy ); if( ToDivide.ParamIsGreater( Test1 )) TestIndex--; } Quotient.SetDigitAndClear( TestIndex, 1 ); Quotient.D[TestIndex] = 0; uint BitTest = 0x80000000; while( true ) { // For-loop to test each bit: for( int BitCount = 31; BitCount >= 0; BitCount-- ) { Test1.Copy( Quotient ); Test1.D[TestIndex] |= BitTest; Test1.Multiply( DivideBy ); if( Test1.ParamIsGreaterOrEq( ToDivide )) Quotient.D[TestIndex] |= BitTest; // Then keep the bit. BitTest >>= 1; } if( TestIndex == 0 ) break; TestIndex--; BitTest = 0x80000000; } Test1.Copy( Quotient ); Test1.Multiply( DivideBy ); if( Test1.IsEqual( ToDivide ) ) { Remainder.SetToZero(); return true; // Divides exactly. } Remainder.Copy( ToDivide ); Remainder.Subtract( Test1 ); // Does not divide it exactly. return false; } */ private void TestDivideBits( ulong MaxValue, bool IsTop, int TestIndex, Integer ToDivide, Integer DivideBy, Integer Quotient, Integer Remainder ) { // For a particular value of TestIndex, this does the // for-loop to test each bit. // When you're not testing you wouldn't want to be creating these // and allocating the RAM for them each time it's called. // Integer Test1 = new Integer(); // Integer Test2 = new Integer(); uint BitTest = 0x80000000; for( int BitCount = 31; BitCount >= 0; BitCount-- ) { if( (Quotient.GetD( TestIndex ) | BitTest) > MaxValue ) { // If it's more than the MaxValue then the // multiplication test can be skipped for // this bit. // SkippedMultiplies++; BitTest >>= 1; continue; } // Is it only doing the multiplication for the top digit? if( IsTop ) { TestForBits.Copy( Quotient ); TestForBits.SetD( TestIndex, TestForBits.GetD( TestIndex ) | BitTest ); MultiplyTop( TestForBits, DivideBy ); /* Test2.Copy( Quotient ); Test2.SetD( TestIndex, Test2.GetD( TestIndex ) | BitTest ); Multiply( Test2, DivideBy ); if( !Test1.IsEqual( Test2 )) throw( new Exception( "!Test1.IsEqual( Test2 ) in TestDivideBits()." )); */ } else { TestForBits.Copy( Quotient ); TestForBits.SetD( TestIndex, TestForBits.GetD( TestIndex ) | BitTest ); Multiply( TestForBits, DivideBy ); } if( TestForBits.ParamIsGreaterOrEq( ToDivide )) Quotient.SetD( TestIndex, Quotient.GetD( TestIndex ) | BitTest ); // Keep the bit. BitTest >>= 1; } }
// This is a variation on ShortDivide that returns the remainder. // Also, DivideBy is a ulong. internal ulong ShortDivideRem( Integer ToDivideOriginal, ulong DivideByU, Integer Quotient ) { if( ToDivideOriginal.IsULong()) { ulong ToDiv = ToDivideOriginal.GetAsULong(); ulong Q = ToDiv / DivideByU; Quotient.SetFromULong( Q ); return ToDiv % DivideByU; } ToDivide.Copy( ToDivideOriginal ); Quotient.Copy( ToDivide ); ulong RemainderU = 0; if( DivideByU > Quotient.GetD( Quotient.GetIndex() )) { Quotient.SetD( Quotient.GetIndex(), 0 ); } else { ulong OneDigit = Quotient.GetD( Quotient.GetIndex() ); Quotient.SetD( Quotient.GetIndex(), OneDigit / DivideByU ); RemainderU = OneDigit % DivideByU; ToDivide.SetD( ToDivide.GetIndex(), RemainderU ); } for( int Count = Quotient.GetIndex(); Count >= 1; Count-- ) { ulong TwoDigits = ToDivide.GetD( Count ); TwoDigits <<= 32; TwoDigits |= ToDivide.GetD( Count - 1 ); Quotient.SetD( Count - 1, TwoDigits / DivideByU ); RemainderU = TwoDigits % DivideByU; ToDivide.SetD( Count, 0 ); ToDivide.SetD( Count - 1, RemainderU ); } for( int Count = Quotient.GetIndex(); Count >= 0; Count-- ) { if( Quotient.GetD( Count ) != 0 ) { Quotient.SetIndex( Count ); break; } } return RemainderU; }
internal void DoSquare( Integer ToSquare ) { if( ToSquare.GetIndex() == 0 ) { ToSquare.Square0(); return; } if( ToSquare.GetIndex() == 1 ) { ToSquare.Square1(); return; } if( ToSquare.GetIndex() == 2 ) { ToSquare.Square2(); return; } // Now Index is at least 3: int DoubleIndex = ToSquare.GetIndex() << 1; if( DoubleIndex >= Integer.DigitArraySize ) { throw( new Exception( "Square() overflowed." )); } for( int Row = 0; Row <= ToSquare.GetIndex(); Row++ ) { if( ToSquare.GetD( Row ) == 0 ) { for( int Column = 0; Column <= ToSquare.GetIndex(); Column++ ) M[Column + Row, Row] = 0; } else { for( int Column = 0; Column <= ToSquare.GetIndex(); Column++ ) M[Column + Row, Row] = ToSquare.GetD( Row ) * ToSquare.GetD( Column ); } } // Add the columns up with a carry. ToSquare.SetD( 0, M[0, 0] & 0xFFFFFFFF ); ulong Carry = M[0, 0] >> 32; for( int Column = 1; Column <= DoubleIndex; Column++ ) { ulong TotalLeft = 0; ulong TotalRight = 0; for( int Row = 0; Row <= Column; Row++ ) { if( Row > ToSquare.GetIndex() ) break; if( Column > (ToSquare.GetIndex() + Row) ) continue; TotalRight += M[Column, Row] & 0xFFFFFFFF; TotalLeft += M[Column, Row] >> 32; } TotalRight += Carry; ToSquare.SetD( Column, TotalRight & 0xFFFFFFFF ); Carry = TotalRight >> 32; Carry += TotalLeft; } ToSquare.SetIndex( DoubleIndex ); if( Carry != 0 ) { ToSquare.SetIndex( ToSquare.GetIndex() + 1 ); if( ToSquare.GetIndex() >= Integer.DigitArraySize ) throw( new Exception( "Square() overflow." )); ToSquare.SetD( ToSquare.GetIndex(), Carry ); } }
internal bool GetProduct( Integer BigIntToSet ) { BigIntToSet.SetToZero(); if( !AllProductBitsAreKnown()) return false; int Highest = GetHighestProductBitIndex(); for( int Row = Highest; Row >= 0; Row-- ) { // The first time through it will just shift zero // to the left, so nothing happens with zero. BigIntToSet.ShiftLeft( 1 ); uint ToSet = MultArray[Row].OneLine[0]; if( GetAccumOutValue( ToSet )) { ulong D = BigIntToSet.GetD( 0 ); D |= 1; BigIntToSet.SetD( 0, D ); } } return true; }