@@ -1913,24 +1913,26 @@ MutableBigInteger[] sqrtRem() {
1913
1913
if (bitLength != (int ) bitLength )
1914
1914
throw new ArithmeticException ("bitLength() integer overflow" );
1915
1915
1916
- return sqrtRemZimmermann (this , this . intLen , false );
1916
+ return sqrtRemZimmermann (this );
1917
1917
}
1918
1918
1919
1919
/**
1920
- * Assume {@code 2 <= limit <= x.intLen}
1920
+ * Assume {@code x.intLen >= 2 }
1921
1921
* @implNote The implementation is based on Zimmermann's works available
1922
1922
* <a href="https://inria.hal.science/inria-00072854/en/"> here</a> and
1923
1923
* <a href="https://www.researchgate.net/publication/220532560_A_proof_of_GMP_square_root"> here</a>
1924
1924
*/
1925
- private static MutableBigInteger [] sqrtRemZimmermann (MutableBigInteger x , int limit , boolean isRecursion ) {
1925
+ private static MutableBigInteger [] sqrtRemZimmermann (MutableBigInteger x ) {
1926
1926
// Normalize leading int
1927
1927
int shift = Integer .numberOfLeadingZeros (x .value [x .offset ]) & ~1 ; // shift must be even
1928
1928
if (shift != 0 ) {
1929
- x = new MutableBigInteger (Arrays .copyOfRange (x .value , x .offset , limit ));
1929
+ x = new MutableBigInteger (Arrays .copyOfRange (x .value , x .offset , x . intLen ));
1930
1930
x .primitiveLeftShift (shift );
1931
1931
}
1932
1932
1933
- if (limit == 2 ) { // Base case
1933
+ MutableBigInteger sqrt , rem ;
1934
+ {
1935
+ // Base case
1934
1936
long hi = x .value [x .offset ] & LONG_MASK , lo = x .value [x .offset + 1 ] & LONG_MASK ;
1935
1937
long s = (long ) Math .sqrt (hi ); // Math.sqrt is exact
1936
1938
long r = hi - s * s ;
@@ -1946,85 +1948,69 @@ private static MutableBigInteger[] sqrtRemZimmermann(MutableBigInteger x, int li
1946
1948
s --;
1947
1949
}
1948
1950
1949
- // Denormalize
1950
- if (shift != 0 ) {
1951
- s >>= (shift >> 1 );
1952
- r = (((hi << 32 ) | lo ) >>> shift ) - s * s ;
1951
+ sqrt = new MutableBigInteger ((int ) s );
1952
+ rem = (r & LONG_MASK ) == r ? new MutableBigInteger ((int ) r )
1953
+ : new MutableBigInteger (new int [] { 1 , (int ) r });
1954
+ }
1955
+
1956
+ // Iterative step
1957
+ int limit ;
1958
+ for (limit = 4 ; limit >> 1 < x .intLen ; limit <<= 1 ) {
1959
+ final int blockLength = limit >> 2 ;
1960
+ MutableBigInteger dividend = x .getBlockZimmermann (1 , limit , blockLength );
1961
+ dividend .addDisjoint (rem , blockLength );
1962
+ MutableBigInteger twiceSqrt = new MutableBigInteger (sqrt );
1963
+ twiceSqrt .leftShift (1 );
1964
+ MutableBigInteger q = new MutableBigInteger ();
1965
+ MutableBigInteger u = dividend .divide (twiceSqrt , q );
1966
+
1967
+ rem = x .getBlockZimmermann (0 , limit , blockLength );
1968
+ rem .addDisjoint (u , blockLength );
1969
+ BigInteger qBig = q .toBigInteger ();
1970
+ MutableBigInteger qSqr = new MutableBigInteger (qBig .multiply (qBig ).mag );
1971
+ int rSign = rem .subtract (qSqr );
1972
+
1973
+ q .addShifted (sqrt , blockLength );
1974
+ sqrt = q ;
1975
+
1976
+ if (rSign == -1 ) {
1977
+ twiceSqrt = new MutableBigInteger (sqrt );
1978
+ twiceSqrt .leftShift (1 );
1979
+
1980
+ rem .subtract (twiceSqrt );
1981
+ rem .add (ONE );
1982
+ sqrt .subtract (ONE );
1953
1983
}
1954
-
1955
- return new MutableBigInteger [] { new MutableBigInteger ((int ) s ),
1956
- (r & LONG_MASK ) == r ? new MutableBigInteger ((int ) r )
1957
- : new MutableBigInteger (new int [] { 1 , (int ) r }) };
1958
- }
1959
-
1960
- // Recursive case (limit >= 3)
1961
-
1962
- // Normalize limit
1963
- if ((limit & 3 ) != 0 ) { // limit must be a multiple of 4
1964
- if (isRecursion ) { // In recursive invocations, limit is even
1965
- int [] xVal = new int [limit + 2 ];
1966
- System .arraycopy (x .value , x .offset , xVal , 0 , limit );
1967
- x = new MutableBigInteger (xVal );
1968
- limit += 2 ;
1969
- shift += 64 ;
1970
- } else {
1971
- int intsToAdd = 4 - (limit & 3 );
1972
- int [] xVal = new int [limit + intsToAdd ];
1973
- System .arraycopy (x .value , x .offset , xVal , 0 , limit );
1974
- x = new MutableBigInteger (xVal );
1975
- limit += intsToAdd ;
1976
- shift += intsToAdd << 5 ;
1977
- }
1978
- }
1979
-
1980
- MutableBigInteger [] sr = sqrtRemZimmermann (x , limit >> 1 , true ); // Recursive invocation
1981
-
1982
- final int blockLength = limit >> 2 ;
1983
- MutableBigInteger dividend = x .getBlockZimmermann (1 , limit , blockLength );
1984
- dividend .addDisjoint (sr [1 ], blockLength );
1985
- MutableBigInteger twiceS = new MutableBigInteger (sr [0 ]);
1986
- twiceS .leftShift (1 );
1987
- MutableBigInteger q = new MutableBigInteger ();
1988
- MutableBigInteger u = dividend .divide (twiceS , q );
1989
-
1990
- MutableBigInteger r = x .getBlockZimmermann (0 , limit , blockLength );
1991
- r .addDisjoint (u , blockLength );
1992
- BigInteger qBig = q .toBigInteger ();
1993
- MutableBigInteger qSqr = new MutableBigInteger (qBig .multiply (qBig ).mag );
1994
- int rSign = r .subtract (qSqr );
1995
-
1996
- MutableBigInteger s = q ;
1997
- s .addShifted (sr [0 ], blockLength );
1998
-
1999
- if (rSign == -1 ) {
2000
- twiceS = new MutableBigInteger (s );
2001
- twiceS .leftShift (1 );
2002
-
2003
- r .subtract (twiceS );
2004
- r .subtract (ONE );
2005
- s .subtract (ONE );
2006
1984
}
1985
+ limit >>= 1 ;
2007
1986
2008
1987
// Denormalize
1988
+ shift += (limit - x .intLen ) << 5 ;
2009
1989
if (shift != 0 ) {
2010
1990
final int halfShift = shift >> 1 ;
2011
- if (!r .isZero ()) {
2012
- BigInteger s0 = s .getBlockZimmermann (0 , s .intLen , (halfShift + 31 ) >> 5 ).toBigInteger ();
2013
- if ((halfShift & 31 ) != 0 )
1991
+ if (!rem .isZero ()) {
1992
+ BigInteger s0 = sqrt .getBlockZimmermann (0 , sqrt .intLen , (halfShift + 31 ) >> 5 ).toBigInteger ();
1993
+ if (s0 . mag . length != 0 && (halfShift & 31 ) != 0 )
2014
1994
s0 .mag [0 ] &= (1 << halfShift ) - 1 ;
2015
1995
2016
- r .add (new MutableBigInteger (s0 .multiply (s .toBigInteger ()).shiftLeft (1 ).mag ));
2017
- r .subtract (new MutableBigInteger (s0 .multiply (s0 ).mag ));
2018
- r .rightShift (shift );
1996
+ rem .add (new MutableBigInteger (s0 .multiply (sqrt .toBigInteger ()).shiftLeft (1 ).mag ));
1997
+ rem .subtract (new MutableBigInteger (s0 .multiply (s0 ).mag ));
1998
+ rem .rightShift (shift );
2019
1999
}
2020
- s .rightShift (halfShift );
2000
+ sqrt .rightShift (halfShift );
2021
2001
}
2022
- return new MutableBigInteger [] { s , r };
2002
+ return new MutableBigInteger [] { sqrt , rem };
2023
2003
}
2024
2004
2025
2005
private MutableBigInteger getBlockZimmermann (int blockIndex , int limit , int blockLength ) {
2026
- int to = offset + limit - (blockIndex * blockLength );
2027
- return new MutableBigInteger (Arrays .copyOfRange (value , to - blockLength , to ));
2006
+ int from = offset + limit - (blockIndex + 1 ) * blockLength ;
2007
+ int intEnd = offset + intLen ;
2008
+ if (from >= intEnd )
2009
+ return new MutableBigInteger ();
2010
+
2011
+ int [] block = new int [blockLength ];
2012
+ System .arraycopy (value , from , block , 0 , Math .min (intEnd - from , blockLength ));
2013
+ return new MutableBigInteger (block );
2028
2014
}
2029
2015
2030
2016
/**
0 commit comments