Skip to content

Commit 7d357d2

Browse files
committed
Omit low precision digits in calculations
1 parent fc72c8d commit 7d357d2

File tree

1 file changed

+44
-20
lines changed
  • ext/bcmath/libbcmath/src

1 file changed

+44
-20
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 44 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -171,16 +171,25 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
171171
guess_vector[guess_arr_size - 3] = initial_guess * BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff];
172172
guess_vector[guess_arr_size - 3] += BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff] - 1;
173173

174-
/* Initialize the uninitialized vector with zeros. */
174+
/* Initialize the uninitialized vector with `BC_VECTOR_BOUNDARY_NUM - 1`. */
175175
for (size_t i = 0; i < guess_arr_size - 3; i++) {
176-
guess_vector[i] = 0;
176+
guess_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
177+
guess1_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
177178
}
178179
guess_vector[guess_arr_size - 1] = 0;
179180

180-
size_t quot_size = n_arr_size - (guess_arr_size - 1) + 1;
181-
182181
BC_VECTOR two[1] = { 2 };
183182

183+
/* The precision (number of vectors) used for the calculation.
184+
* Since the initial value uses two vectors, the initial precision is set to 2. */
185+
size_t guess_precision = 2;
186+
size_t guess_offset = guess_arr_size - 1 - guess_precision;
187+
size_t n_offset = guess_offset * 2;
188+
size_t n_precision = n_arr_size - n_offset;
189+
size_t quot_size = n_precision - (guess_precision) + 1;
190+
size_t guess_use_len = guess_top_vector_len + BC_VECTOR_SIZE;
191+
bool updated_precision = false;
192+
184193
/**
185194
* Newton's algorithm. Iterative expression is `x_{n+1} = (x_n + a / x_n) / 2`
186195
* If break down the calculation into detailed steps, it looks like this:
@@ -191,14 +200,23 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
191200
*/
192201
bool done = false;
193202
do {
203+
if (updated_precision) {
204+
guess_offset = guess_arr_size - 1 - guess_precision;
205+
n_offset = guess_offset * 2;
206+
n_precision = n_arr_size - n_offset;
207+
quot_size = n_precision - (guess_precision) + 1;
208+
guess_use_len = guess_top_vector_len + (guess_precision - 1) * BC_VECTOR_SIZE;
209+
updated_precision = false;
210+
}
211+
194212
/* Since the value changes during division by successive approximation, use a copied version of it. */
195-
memcpy(n_vector_copy, n_vector, n_arr_size * sizeof(BC_VECTOR));
213+
memcpy(n_vector_copy + n_offset, n_vector + n_offset, n_precision * sizeof(BC_VECTOR));
196214

197215
/* 1. quot = a / x_n */
198216
bc_divide_vector(
199-
n_vector_copy, n_arr_size,
200-
guess_vector, guess_arr_size - 1, guess_full_len,
201-
tmp_div_ret_vector, quot_size
217+
n_vector_copy + n_offset, n_precision,
218+
guess_vector + guess_offset, guess_precision, guess_use_len,
219+
tmp_div_ret_vector + guess_offset, quot_size
202220
);
203221

204222
BC_VECTOR *tmp_vptr = guess1_vector;
@@ -207,7 +225,7 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
207225

208226
/* 2. add = x_n + quot1 */
209227
int carry = 0;
210-
for (size_t i = 0; i < guess_arr_size - 1; i++) {
228+
for (size_t i = guess_offset; i < guess_arr_size - 1; i++) {
211229
guess_vector[i] = guess1_vector[i] + tmp_div_ret_vector[i] + carry;
212230
if (guess_vector[i] >= BC_VECTOR_BOUNDARY_NUM) {
213231
guess_vector[i] -= BC_VECTOR_BOUNDARY_NUM;
@@ -220,24 +238,30 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
220238

221239
/* 3. x_{n+1} = add / 2 */
222240
bc_divide_vector(
223-
guess_vector, guess_arr_size,
241+
guess_vector + guess_offset, guess_precision + 1,
224242
two, 1, 1,
225-
tmp_div_ret_vector, guess_arr_size
243+
tmp_div_ret_vector + guess_offset, guess_precision + 1
226244
);
227245

228-
memcpy(guess_vector, tmp_div_ret_vector, guess_arr_size * sizeof(BC_VECTOR));
246+
memcpy(guess_vector + guess_offset, tmp_div_ret_vector + guess_offset, guess_precision * sizeof(BC_VECTOR));
229247

230248
/* 4. repeat until the difference between the `x_n` and `x_{n+1}` is less than or equal to 1. */
231-
size_t diff = guess_vector[0] > guess1_vector[0] ? guess_vector[0] - guess1_vector[0] : guess1_vector[0] - guess_vector[0];
232-
if (diff <= 1) {
233-
bool is_same = true;
234-
for (size_t i = 1; i < guess_arr_size - 1; i++) {
235-
if (guess_vector[i] != guess1_vector[i]) {
236-
is_same = false;
237-
break;
249+
if (guess_precision < guess_arr_size - 1) {
250+
/* If the precision has not yet reached the maximum number of digits, it will be increased. */
251+
guess_precision = MIN(guess_precision * 2, guess_arr_size - 1);
252+
updated_precision = true;
253+
} else {
254+
size_t diff = guess_vector[0] > guess1_vector[0] ? guess_vector[0] - guess1_vector[0] : guess1_vector[0] - guess_vector[0];
255+
if (diff <= 1) {
256+
bool is_same = true;
257+
for (size_t i = 1; i < guess_arr_size - 1; i++) {
258+
if (guess_vector[i] != guess1_vector[i]) {
259+
is_same = false;
260+
break;
261+
}
238262
}
263+
done = is_same;
239264
}
240-
done = is_same;
241265
}
242266
} while (!done);
243267

0 commit comments

Comments
 (0)