// 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; }
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 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; }
// 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 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(); }
// 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 } */ }
// 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 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 )); } }