Skip to content

Commit 03f3124

Browse files
committed
Omit low precision digits in calculations
1 parent a980339 commit 03f3124

File tree

1 file changed

+45
-21
lines changed
  • ext/bcmath/libbcmath/src

1 file changed

+45
-21
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -174,16 +174,25 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
174174
initial_guess %= BC_POW_10_LUT[guess_len_diff];
175175
guess_vector[guess_arr_size - 3] = initial_guess * BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff];
176176

177-
/* Initialize the uninitialized vector with zeros. */
177+
/* Initialize the uninitialized vector with `BC_VECTOR_BOUNDARY_NUM - 1`. */
178178
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;
180181
}
181182
guess_vector[guess_arr_size - 1] = 0;
182183

183-
size_t quot_size = n_arr_size - (guess_arr_size - 1) + 1;
184-
185184
BC_VECTOR two[1] = { 2 };
186185

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+
187196
/**
188197
* Newton's algorithm. Iterative expression is `x_{n+1} = (x_n + a / x_n) / 2`
189198
* If break down the calculation into detailed steps, it looks like this:
@@ -194,14 +203,23 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
194203
*/
195204
bool done = false;
196205
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+
197215
/* Since the value changes during division by successive approximation, use a copied version of it. */
198-
memcpy(n_vector_copy, n_vector, n_arr_size * sizeof(BC_VECTOR));
216+
memcpy(n_vector_copy + n_offset, n_vector + n_offset, n_precision * sizeof(BC_VECTOR));
199217

200218
/* 1. quot = a / x_n */
201219
bc_divide_vector(
202-
n_vector_copy, n_arr_size,
203-
guess_vector, guess_arr_size - 1, guess_full_len,
204-
tmp_div_ret_vector, quot_size
220+
n_vector_copy + n_offset, n_precision,
221+
guess_vector + guess_offset, guess_precision, guess_use_len,
222+
tmp_div_ret_vector + guess_offset, quot_size
205223
);
206224

207225
BC_VECTOR *tmp_vptr = guess1_vector;
@@ -210,7 +228,7 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
210228

211229
/* 2. add = x_n + quot1 */
212230
int carry = 0;
213-
for (size_t i = 0; i < guess_arr_size - 1; i++) {
231+
for (size_t i = guess_offset; i < guess_arr_size; i++) {
214232
guess_vector[i] = guess1_vector[i] + tmp_div_ret_vector[i] + carry;
215233
if (guess_vector[i] >= BC_VECTOR_BOUNDARY_NUM) {
216234
guess_vector[i] -= BC_VECTOR_BOUNDARY_NUM;
@@ -219,28 +237,34 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
219237
carry = 0;
220238
}
221239
}
222-
guess_vector[guess_arr_size - 1] = carry;
240+
guess_vector[guess_arr_size - 1] = tmp_div_ret_vector[guess_arr_size - 1] + carry;
223241

224242
/* 3. x_{n+1} = add / 2 */
225243
bc_divide_vector(
226-
guess_vector, guess_arr_size,
244+
guess_vector + guess_offset, guess_precision + 1,
227245
two, 1, 1,
228-
tmp_div_ret_vector, guess_arr_size
246+
tmp_div_ret_vector + guess_offset, guess_precision + 1
229247
);
230248

231-
memcpy(guess_vector, tmp_div_ret_vector, guess_arr_size * sizeof(BC_VECTOR));
249+
memcpy(guess_vector + guess_offset, tmp_div_ret_vector + guess_offset, guess_precision * sizeof(BC_VECTOR));
232250

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

0 commit comments

Comments
 (0)