Skip to content

Commit 16c6ca0

Browse files
committed
Omit low precision digits in calculations
1 parent cbd2aed commit 16c6ca0

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
@@ -165,16 +165,25 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
165165
guess_vector[guess_arr_size - 3] = initial_guess * BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff];
166166
guess_vector[guess_arr_size - 3] += BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff] - 1;
167167

168-
/* Initialize the uninitialized vector with zeros. */
168+
/* Initialize the uninitialized vector with `BC_VECTOR_BOUNDARY_NUM - 1`. */
169169
for (size_t i = 0; i < guess_arr_size - 3; i++) {
170-
guess_vector[i] = 0;
170+
guess_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
171+
guess1_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
171172
}
172173
guess_vector[guess_arr_size - 1] = 0;
173174

174-
size_t quot_size = n_arr_size - (guess_arr_size - 1) + 1;
175-
176175
BC_VECTOR two[1] = { 2 };
177176

177+
/* The precision (number of vectors) used for the calculation.
178+
* Since the initial value uses two vectors, the initial precision is set to 2. */
179+
size_t guess_precision = 2;
180+
size_t guess_offset = guess_arr_size - 1 - guess_precision;
181+
size_t n_offset = guess_offset * 2;
182+
size_t n_precision = n_arr_size - n_offset;
183+
size_t quot_size = n_precision - (guess_precision) + 1;
184+
size_t guess_use_len = guess_top_vector_len + BC_VECTOR_SIZE;
185+
bool updated_precision = false;
186+
178187
/**
179188
* Newton's algorithm. Iterative expression is `x_{n+1} = (x_n + a / x_n) / 2`
180189
* If break down the calculation into detailed steps, it looks like this:
@@ -185,14 +194,23 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
185194
*/
186195
bool done = false;
187196
do {
197+
if (updated_precision) {
198+
guess_offset = guess_arr_size - 1 - guess_precision;
199+
n_offset = guess_offset * 2;
200+
n_precision = n_arr_size - n_offset;
201+
quot_size = n_precision - (guess_precision) + 1;
202+
guess_use_len = guess_top_vector_len + (guess_precision - 1) * BC_VECTOR_SIZE;
203+
updated_precision = false;
204+
}
205+
188206
/* Since the value changes during division by successive approximation, use a copied version of it. */
189-
memcpy(n_vector_copy, n_vector, n_arr_size * sizeof(BC_VECTOR));
207+
memcpy(n_vector_copy + n_offset, n_vector + n_offset, n_precision * sizeof(BC_VECTOR));
190208

191209
/* 1. quot = a / x_n */
192210
bc_divide_vector(
193-
n_vector_copy, n_arr_size,
194-
guess_vector, guess_arr_size - 1, guess_full_len,
195-
tmp_div_ret_vector, quot_size
211+
n_vector_copy + n_offset, n_precision,
212+
guess_vector + guess_offset, guess_precision, guess_use_len,
213+
tmp_div_ret_vector + guess_offset, quot_size
196214
);
197215

198216
BC_VECTOR *tmp_vptr = guess1_vector;
@@ -201,7 +219,7 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
201219

202220
/* 2. add = x_n + quot1 */
203221
int carry = 0;
204-
for (size_t i = 0; i < guess_arr_size - 1; i++) {
222+
for (size_t i = guess_offset; i < guess_arr_size - 1; i++) {
205223
guess_vector[i] = guess1_vector[i] + tmp_div_ret_vector[i] + carry;
206224
if (guess_vector[i] >= BC_VECTOR_BOUNDARY_NUM) {
207225
guess_vector[i] -= BC_VECTOR_BOUNDARY_NUM;
@@ -214,24 +232,30 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
214232

215233
/* 3. x_{n+1} = add / 2 */
216234
bc_divide_vector(
217-
guess_vector, guess_arr_size,
235+
guess_vector + guess_offset, guess_precision + 1,
218236
two, 1, 1,
219-
tmp_div_ret_vector, guess_arr_size
237+
tmp_div_ret_vector + guess_offset, guess_precision + 1
220238
);
221239

222-
memcpy(guess_vector, tmp_div_ret_vector, guess_arr_size * sizeof(BC_VECTOR));
240+
memcpy(guess_vector + guess_offset, tmp_div_ret_vector + guess_offset, guess_precision * sizeof(BC_VECTOR));
223241

224242
/* 4. repeat until the difference between the `x_n` and `x_{n+1}` is less than or equal to 1. */
225-
size_t diff = guess_vector[0] > guess1_vector[0] ? guess_vector[0] - guess1_vector[0] : guess1_vector[0] - guess_vector[0];
226-
if (diff <= 1) {
227-
bool is_same = true;
228-
for (size_t i = 1; i < guess_arr_size - 1; i++) {
229-
if (guess_vector[i] != guess1_vector[i]) {
230-
is_same = false;
231-
break;
243+
if (guess_precision < guess_arr_size - 1) {
244+
/* If the precision has not yet reached the maximum number of digits, it will be increased. */
245+
guess_precision = MIN(guess_precision * 2, guess_arr_size - 1);
246+
updated_precision = true;
247+
} else {
248+
size_t diff = guess_vector[0] > guess1_vector[0] ? guess_vector[0] - guess1_vector[0] : guess1_vector[0] - guess_vector[0];
249+
if (diff <= 1) {
250+
bool is_same = true;
251+
for (size_t i = 1; i < guess_arr_size - 1; i++) {
252+
if (guess_vector[i] != guess1_vector[i]) {
253+
is_same = false;
254+
break;
255+
}
232256
}
257+
done = is_same;
233258
}
234-
done = is_same;
235259
}
236260
} while (!done);
237261

0 commit comments

Comments
 (0)