@@ -1882,6 +1882,151 @@ MutableBigInteger sqrt() {
1882
1882
}
1883
1883
}
1884
1884
1885
+ /**
1886
+ * Calculate the integer square root {@code floor(sqrt(this))} and the remainder,
1887
+ * where {@code sqrt(.)} denotes the mathematical square root.
1888
+ * The contents of {@code this} are <b>not</b> changed.
1889
+ * The value of {@code this} is assumed to be non-negative.
1890
+ * @throws ArithmeticException if the value returned by {@code bitLength()}
1891
+ * overflows the range of {@code int}.
1892
+ * @return the integer square root of {@code this}
1893
+ */
1894
+ MutableBigInteger [] sqrtRem () {
1895
+ // Special cases.
1896
+ if (this .isZero ()) {
1897
+ return new MutableBigInteger [] { this , this };
1898
+ } else if (this .intLen == 1 ) {
1899
+ MutableBigInteger r = new MutableBigInteger (this );
1900
+
1901
+ final long val = this .value [offset ] & LONG_MASK ;
1902
+ if (val < 4 ) { // result is unity
1903
+ r .subtract (ONE );
1904
+ return new MutableBigInteger [] { ONE , r };
1905
+ }
1906
+
1907
+ int s = (int ) Math .sqrt (val ); // Math.sqrt is exact
1908
+ r .subtract (new MutableBigInteger (s * s ));
1909
+ return new MutableBigInteger [] { new MutableBigInteger (s ), r };
1910
+ }
1911
+
1912
+ long bitLength = this .bitLength ();
1913
+ if (bitLength != (int ) bitLength )
1914
+ throw new ArithmeticException ("bitLength() integer overflow" );
1915
+
1916
+ return sqrtRemZimmermann (this , this .intLen , false );
1917
+ }
1918
+
1919
+ /**
1920
+ * Assume {@code 2 <= limit <= x.intLen}
1921
+ * @implNote The implementation is based on Zimmermann's works available
1922
+ * <a href="https://inria.hal.science/inria-00072854/en/"> here</a> and
1923
+ * <a href="https://www.researchgate.net/publication/220532560_A_proof_of_GMP_square_root"> here</a>
1924
+ */
1925
+ private static MutableBigInteger [] sqrtRemZimmermann (MutableBigInteger x , int limit , boolean isRecursion ) {
1926
+ // Normalize leading int
1927
+ int shift = Integer .numberOfLeadingZeros (x .value [x .offset ]) & ~1 ; // shift must be even
1928
+ if (shift != 0 ) {
1929
+ x = new MutableBigInteger (Arrays .copyOfRange (x .value , x .offset , limit ));
1930
+ x .primitiveLeftShift (shift );
1931
+ }
1932
+
1933
+ if (limit == 2 ) { // Base case
1934
+ long hi = x .value [x .offset ] & LONG_MASK , lo = x .value [x .offset + 1 ] & LONG_MASK ;
1935
+ long s = (long ) Math .sqrt (hi ); // Math.sqrt is exact
1936
+ long r = hi - s * s ;
1937
+
1938
+ final long dividend = (r << 16 ) | (lo >> 16 ), divisor = s << 1 ;
1939
+ final long q = dividend / divisor ;
1940
+ final long u = dividend % divisor ;
1941
+ s = (s << 16 ) + q ;
1942
+ r = ((u << 16 ) | (lo & 0xffffL )) - q * q ;
1943
+
1944
+ if (r < 0 ) {
1945
+ r += (s << 1 ) - 1 ;
1946
+ s --;
1947
+ }
1948
+
1949
+ // Denormalize
1950
+ if (shift != 0 ) {
1951
+ s >>= (shift >> 1 );
1952
+ r = (((hi << 32 ) | lo ) >>> shift ) - s * s ;
1953
+ }
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
+ }
2007
+
2008
+ // Denormalize
2009
+ if (shift != 0 ) {
2010
+ 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 )
2014
+ s0 .mag [0 ] &= (1 << halfShift ) - 1 ;
2015
+
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 );
2019
+ }
2020
+ s .rightShift (halfShift );
2021
+ }
2022
+ return new MutableBigInteger [] { s , r };
2023
+ }
2024
+
2025
+ 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 ));
2028
+ }
2029
+
1885
2030
/**
1886
2031
* Calculate GCD of this and b. This and b are changed by the computation.
1887
2032
*/
0 commit comments