@@ -6878,63 +6878,11 @@ BDIGIT rb_bdigit_dbl_isqrt(BDIGIT_DBL);
68786878# define BDIGIT_DBL_TO_DOUBLE (n ) (double)(n)
68796879#endif
68806880
6881- static BDIGIT *
6882- estimate_initial_sqrt (VALUE * xp , const size_t xn , const BDIGIT * nds , size_t len )
6883- {
6884- enum {dbl_per_bdig = roomof (DBL_MANT_DIG ,BITSPERDIG )};
6885- const int zbits = nlz (nds [len - 1 ]);
6886- VALUE x = * xp = bignew_1 (0 , xn , 1 ); /* division may release the GVL */
6887- BDIGIT * xds = BDIGITS (x );
6888- BDIGIT_DBL d = bary2bdigitdbl (nds + len - dbl_per_bdig , dbl_per_bdig );
6889- BDIGIT lowbits = 1 ;
6890- int rshift = (int )((BITSPERDIG * 2 - zbits + (len & BITSPERDIG & 1 ) - DBL_MANT_DIG + 1 ) & ~1 );
6891- double f ;
6892-
6893- if (rshift > 0 ) {
6894- lowbits = (BDIGIT )d & ~(~(BDIGIT )1U << rshift );
6895- d >>= rshift ;
6896- }
6897- else if (rshift < 0 ) {
6898- d <<= - rshift ;
6899- d |= nds [len - dbl_per_bdig - 1 ] >> (BITSPERDIG + rshift );
6900- }
6901- f = sqrt (BDIGIT_DBL_TO_DOUBLE (d ));
6902- d = (BDIGIT_DBL )ceil (f );
6903- if (BDIGIT_DBL_TO_DOUBLE (d ) == f ) {
6904- if (lowbits || (lowbits = !bary_zero_p (nds , len - dbl_per_bdig )))
6905- ++ d ;
6906- }
6907- else {
6908- lowbits = 1 ;
6909- }
6910- rshift /= 2 ;
6911- rshift += (2 - (len & 1 ))* BITSPERDIG /2 ;
6912- if (rshift >= 0 ) {
6913- if (nlz ((BDIGIT )d ) + rshift >= BITSPERDIG ) {
6914- /* (d << rshift) does cause overflow.
6915- * example: Integer.sqrt(0xffff_ffff_ffff_ffff ** 2)
6916- */
6917- d = ~(BDIGIT_DBL )0 ;
6918- }
6919- else {
6920- d <<= rshift ;
6921- }
6922- }
6923- BDIGITS_ZERO (xds , xn - 2 );
6924- bdigitdbl2bary (& xds [xn - 2 ], 2 , d );
6925-
6926- if (!lowbits ) return NULL ; /* special case, exact result */
6927- return xds ;
6928- }
6929-
69306881VALUE
69316882rb_big_isqrt (VALUE n )
69326883{
69336884 BDIGIT * nds = BDIGITS (n );
69346885 size_t len = BIGNUM_LEN (n );
6935- size_t xn = (len + 1 ) / 2 ;
6936- VALUE x ;
6937- BDIGIT * xds ;
69386886
69396887 if (len <= 2 ) {
69406888 BDIGIT sq = rb_bdigit_dbl_isqrt (bary2bdigitdbl (nds , len ));
@@ -6944,25 +6892,19 @@ rb_big_isqrt(VALUE n)
69446892 return ULONG2NUM (sq );
69456893#endif
69466894 }
6947- else if ((xds = estimate_initial_sqrt (& x , xn , nds , len )) != 0 ) {
6948- size_t tn = xn + BIGDIVREM_EXTRA_WORDS ;
6949- VALUE t = bignew_1 (0 , tn , 1 );
6950- BDIGIT * tds = BDIGITS (t );
6951- tn = BIGNUM_LEN (t );
6952-
6953- /* t = n/x */
6954- while (bary_divmod_branch (tds , tn , NULL , 0 , nds , len , xds , xn ),
6955- bary_cmp (tds , tn , xds , xn ) < 0 ) {
6956- int carry ;
6957- BARY_TRUNC (tds , tn );
6958- /* x = (x+t)/2 */
6959- carry = bary_add (xds , xn , xds , xn , tds , tn );
6960- bary_small_rshift (xds , xds , xn , 1 , carry );
6961- tn = BIGNUM_LEN (t );
6962- }
6895+ else {
6896+ size_t shift = FIX2LONG (rb_big_bit_length (n )) / 4 ;
6897+ VALUE n2 = rb_int_rshift (n , SIZET2NUM (2 * shift ));
6898+ VALUE x = FIXNUM_P (n2 ) ? LONG2FIX (rb_ulong_isqrt (FIX2ULONG (n2 ))) : rb_big_isqrt (n2 );
6899+ /* x = (x+n/x)/2 */
6900+ x = rb_int_plus (rb_int_lshift (x , SIZET2NUM (shift - 1 )), rb_int_idiv (rb_int_rshift (n , SIZET2NUM (shift + 1 )), x ));
6901+ VALUE xx = rb_int_mul (x , x );
6902+ while (rb_int_gt (xx , n )) {
6903+ xx = rb_int_minus (xx , rb_int_minus (rb_int_plus (x , x ), INT2FIX (1 )));
6904+ x = rb_int_minus (x , INT2FIX (1 ));
6905+ }
6906+ return x ;
69636907 }
6964- RBASIC_SET_CLASS_RAW (x , rb_cInteger );
6965- return x ;
69666908}
69676909
69686910#if USE_GMP
0 commit comments