Skip to content

Commit 0bf3d72

Browse files
committed
Omit low precision digits in calculations
1 parent 90694a0 commit 0bf3d72

File tree

1 file changed

+35
-10
lines changed
  • ext/bcmath/libbcmath/src

1 file changed

+35
-10
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 35 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,12 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
180180
}
181181
guess_vector[guess_arr_size - 1] = 0;
182182

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

185+
/* The precision (number of vectors) used for the calculation.
186+
* Since the initial value uses two vectors, the initial precision is set to 2. */
187+
size_t guess_precision = 2;
188+
187189
/**
188190
* Newton's algorithm. Iterative expression is `x_{n+1} = (x_n + a / x_n) / 2`
189191
* If break down the calculation into detailed steps, it looks like this:
@@ -194,13 +196,23 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
194196
*/
195197
bool done = false;
196198
do {
199+
size_t guess_offset = guess_arr_size - 1 - guess_precision;
200+
size_t n_offset = guess_offset * 2;
201+
197202
/* 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++) {
203+
for (size_t i = n_offset; i < n_arr_size; i++) {
199204
n_vector_copy[i] = n_vector[i];
200205
}
201206

207+
size_t n_precision = n_arr_size - n_offset;
208+
size_t quot_size = n_precision - (guess_precision) + 1;
209+
202210
/* 1. quot = a / x_n */
203-
bool div_ret = bc_divide_vector(n_vector_copy, n_arr_size, guess_vector, guess_arr_size - 1, tmp_div_ret_vector, quot_size);
211+
bool div_ret = bc_divide_vector(
212+
n_vector_copy + n_offset, n_precision,
213+
guess_vector + guess_offset, guess_precision,
214+
tmp_div_ret_vector + guess_offset, quot_size
215+
);
204216
ZEND_ASSERT(div_ret);
205217

206218
BC_VECTOR *tmp_vptr = guess1_vector;
@@ -209,7 +221,7 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
209221

210222
/* 2. add = x_n + quot1 */
211223
int carry = 0;
212-
for (size_t i = 0; i < guess_arr_size - 1; i++) {
224+
for (size_t i = guess_offset; i < guess_arr_size; i++) {
213225
guess_vector[i] = guess1_vector[i] + tmp_div_ret_vector[i] + carry;
214226
if (guess_vector[i] >= BC_VECTOR_BOUNDARY_NUM) {
215227
guess_vector[i] -= BC_VECTOR_BOUNDARY_NUM;
@@ -221,24 +233,37 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
221233
guess_vector[guess_arr_size - 1] = carry;
222234

223235
/* 3. x_{n+1} = add / 2 */
224-
div_ret = bc_divide_vector(guess_vector, guess_arr_size, two, 1, tmp_div_ret_vector, guess_arr_size);
236+
div_ret = bc_divide_vector(
237+
guess_vector + guess_offset, guess_precision + 1,
238+
two, 1,
239+
tmp_div_ret_vector + guess_offset, guess_precision + 1
240+
);
225241
ZEND_ASSERT(div_ret);
226242

227-
for (size_t i = 0; i < guess_arr_size; i++) {
243+
for (size_t i = guess_offset; i < guess_arr_size; i++) {
228244
guess_vector[i] = tmp_div_ret_vector[i];
229245
}
230246

231247
/* 4. repeat until the difference between the `x_n` and `x_{n+1}` is less than or equal to 1. */
232-
size_t diff = guess_vector[0] > guess1_vector[0] ? guess_vector[0] - guess1_vector[0] : guess1_vector[0] - guess_vector[0];
248+
size_t diff = guess_vector[guess_offset] > guess1_vector[guess_offset]
249+
? guess_vector[guess_offset] - guess1_vector[guess_offset]
250+
: guess1_vector[guess_offset] - guess_vector[guess_offset];
233251
if (diff <= 1) {
234252
bool is_same = true;
235-
for (size_t i = 1; i < guess_arr_size - 1; i++) {
253+
for (size_t i = guess_offset + 1; i < guess_arr_size - 1; i++) {
236254
if (guess_vector[i] != guess1_vector[i]) {
237255
is_same = false;
238256
break;
239257
}
240258
}
241-
done = is_same;
259+
if (is_same) {
260+
if (guess_precision < guess_arr_size - 1) {
261+
/* If the precision has not yet reached the maximum number of digits, it will be increased. */
262+
guess_precision = MIN(guess_precision * 3, guess_arr_size - 1);
263+
} else {
264+
done = is_same;
265+
}
266+
}
242267
}
243268
} while (!done);
244269

0 commit comments

Comments
 (0)