@@ -174,16 +174,25 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
174
174
initial_guess %= BC_POW_10_LUT [guess_len_diff ];
175
175
guess_vector [guess_arr_size - 3 ] = initial_guess * BC_POW_10_LUT [BC_VECTOR_SIZE - guess_len_diff ];
176
176
177
- /* Initialize the uninitialized vector with zeros . */
177
+ /* Initialize the uninitialized vector with `BC_VECTOR_BOUNDARY_NUM - 1` . */
178
178
for (size_t i = 0 ; i < guess_arr_size - 3 ; i ++ ) {
179
- guess_vector [i ] = 0 ;
179
+ guess_vector [i ] = BC_VECTOR_BOUNDARY_NUM - 1 ;
180
+ guess1_vector [i ] = BC_VECTOR_BOUNDARY_NUM - 1 ;
180
181
}
181
182
guess_vector [guess_arr_size - 1 ] = 0 ;
182
183
183
- size_t quot_size = n_arr_size - (guess_arr_size - 1 ) + 1 ;
184
-
185
184
BC_VECTOR two [1 ] = { 2 };
186
185
186
+ /* The precision (number of vectors) used for the calculation.
187
+ * Since the initial value uses two vectors, the initial precision is set to 2. */
188
+ size_t guess_precision = 2 ;
189
+ size_t guess_offset = guess_arr_size - 1 - guess_precision ;
190
+ size_t n_offset = guess_offset * 2 ;
191
+ size_t n_precision = n_arr_size - n_offset ;
192
+ size_t quot_size = n_precision - (guess_precision ) + 1 ;
193
+ size_t guess_use_len = guess_top_vector_len + BC_VECTOR_SIZE ;
194
+ bool updated_precision = false;
195
+
187
196
/**
188
197
* Newton's algorithm. Iterative expression is `x_{n+1} = (x_n + a / x_n) / 2`
189
198
* If break down the calculation into detailed steps, it looks like this:
@@ -194,16 +203,25 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
194
203
*/
195
204
bool done = false;
196
205
do {
206
+ if (updated_precision ) {
207
+ guess_offset = guess_arr_size - 1 - guess_precision ;
208
+ n_offset = guess_offset * 2 ;
209
+ n_precision = n_arr_size - n_offset ;
210
+ quot_size = n_precision - (guess_precision ) + 1 ;
211
+ guess_use_len = guess_top_vector_len + (guess_precision - 1 ) * BC_VECTOR_SIZE ;
212
+ updated_precision = false;
213
+ }
214
+
197
215
/* Since the value changes during division by successive approximation, use a copied version of it. */
198
- for (size_t i = 0 ; i < n_arr_size ; i ++ ) {
216
+ for (size_t i = n_offset ; i < n_arr_size ; i ++ ) {
199
217
n_vector_copy [i ] = n_vector [i ];
200
218
}
201
219
202
220
/* 1. quot = a / x_n */
203
221
bc_divide_vector (
204
- n_vector_copy , n_arr_size ,
205
- guess_vector , guess_arr_size - 1 , guess_full_len ,
206
- tmp_div_ret_vector , quot_size
222
+ n_vector_copy + n_offset , n_precision ,
223
+ guess_vector + guess_offset , guess_precision , guess_use_len ,
224
+ tmp_div_ret_vector + guess_offset , quot_size
207
225
);
208
226
209
227
BC_VECTOR * tmp_vptr = guess1_vector ;
@@ -212,7 +230,7 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
212
230
213
231
/* 2. add = x_n + quot1 */
214
232
int carry = 0 ;
215
- for (size_t i = 0 ; i < guess_arr_size - 1 ; i ++ ) {
233
+ for (size_t i = guess_offset ; i < guess_arr_size ; i ++ ) {
216
234
guess_vector [i ] = guess1_vector [i ] + tmp_div_ret_vector [i ] + carry ;
217
235
if (guess_vector [i ] >= BC_VECTOR_BOUNDARY_NUM ) {
218
236
guess_vector [i ] -= BC_VECTOR_BOUNDARY_NUM ;
@@ -221,30 +239,41 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
221
239
carry = 0 ;
222
240
}
223
241
}
224
- guess_vector [guess_arr_size - 1 ] = carry ;
242
+ guess_vector [guess_arr_size - 1 ] = tmp_div_ret_vector [ guess_arr_size - 1 ] + carry ;
225
243
226
244
/* 3. x_{n+1} = add / 2 */
227
245
bc_divide_vector (
228
- guess_vector , guess_arr_size ,
246
+ guess_vector + guess_offset , guess_precision + 1 ,
229
247
two , 1 , 1 ,
230
- tmp_div_ret_vector , guess_arr_size
248
+ tmp_div_ret_vector + guess_offset , guess_precision + 1
231
249
);
232
250
233
- for (size_t i = 0 ; i < guess_arr_size ; i ++ ) {
251
+ for (size_t i = guess_offset ; i < guess_arr_size ; i ++ ) {
234
252
guess_vector [i ] = tmp_div_ret_vector [i ];
235
253
}
254
+ /* When estimating the square root of a number like 99,999,999, the result may sometimes have too many digits.
255
+ * In such cases, the value is adjusted (corrected). */
256
+ if (UNEXPECTED (tmp_div_ret_vector [guess_arr_size - 1 ] > 0 )) {
257
+ guess_vector [guess_arr_size - 1 ] = BC_VECTOR_BOUNDARY_NUM - 1 ;
258
+ }
236
259
237
260
/* 4. repeat until the difference between the `x_n` and `x_{n+1}` is less than or equal to 1. */
238
- size_t diff = guess_vector [0 ] > guess1_vector [0 ] ? guess_vector [0 ] - guess1_vector [0 ] : guess1_vector [0 ] - guess_vector [0 ];
239
- if (diff <= 1 ) {
240
- bool is_same = true;
241
- for (size_t i = 1 ; i < guess_arr_size - 1 ; i ++ ) {
242
- if (guess_vector [i ] != guess1_vector [i ]) {
243
- is_same = false;
244
- break ;
261
+ if (guess_precision < guess_arr_size - 1 ) {
262
+ /* If the precision has not yet reached the maximum number of digits, it will be increased. */
263
+ guess_precision = MIN (guess_precision * 2 , guess_arr_size - 1 );
264
+ updated_precision = true;
265
+ } else {
266
+ size_t diff = guess_vector [0 ] > guess1_vector [0 ] ? guess_vector [0 ] - guess1_vector [0 ] : guess1_vector [0 ] - guess_vector [0 ];
267
+ if (diff <= 1 ) {
268
+ bool is_same = true;
269
+ for (size_t i = 1 ; i < guess_arr_size - 1 ; i ++ ) {
270
+ if (guess_vector [i ] != guess1_vector [i ]) {
271
+ is_same = false;
272
+ break ;
273
+ }
245
274
}
275
+ done = is_same ;
246
276
}
247
- done = is_same ;
248
277
}
249
278
} while (!done );
250
279
0 commit comments