Skip to content

Commit 9abc169

Browse files
committed
Efficiently obtain the initial value for the standard path.
1 parent bab712b commit 9abc169

File tree

1 file changed

+40
-11
lines changed
  • ext/bcmath/libbcmath/src

1 file changed

+40
-11
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -137,18 +137,47 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
137137
const char *nend = (*num)->n_value + leading_zeros + num_use_full_len - 1;
138138
bc_convert_to_vector_with_zero_pad(n_vector, nend, num_use_full_len, num_calc_full_len - num_use_full_len);
139139

140-
/* Prepare guess_vector (Temporary implementation) */
141-
for (size_t i = 0; i < guess_arr_size - 2; i++) {
142-
guess_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
140+
/* Prepare guess_vector. Use `bc_fast_sqrt_vector()` to quickly obtain a highly accurate initial value. */
141+
142+
/* 18 on 64-bit, 10 on 32-bit */
143+
size_t n_top_len_for_initial_guess = (MAX_LENGTH_OF_LONG - 1) & ~1;
144+
145+
/* Set the number of digits of num to be used as the initial value for Newton's method.
146+
* Just as the square roots of 1000 and 100 differ significantly, the number of digits
147+
* to "ignore" here must be even. */
148+
if (num_calc_full_len & 1) {
149+
n_top_len_for_initial_guess--;
143150
}
144-
if (guess_full_len % BC_VECTOR_SIZE == 0) {
145-
guess_vector[guess_arr_size - 2] = BC_VECTOR_BOUNDARY_NUM - 1;
146-
} else {
147-
guess_vector[guess_arr_size - 2] = 0;
148-
for (size_t i = 0; i < guess_full_len % BC_VECTOR_SIZE; i++) {
149-
guess_vector[guess_arr_size - 2] *= BASE;
150-
guess_vector[guess_arr_size - 2] += 9;
151-
}
151+
152+
BC_VECTOR n_top = n_vector[n_arr_size - 1];
153+
size_t n_top_index = n_arr_size - 2;
154+
size_t n_top_vector_len = num_calc_full_len % BC_VECTOR_SIZE == 0 ? BC_VECTOR_SIZE : num_calc_full_len % BC_VECTOR_SIZE;
155+
size_t count = n_top_len_for_initial_guess - n_top_vector_len;
156+
while (count >= BC_VECTOR_SIZE) {
157+
n_top *= BC_VECTOR_BOUNDARY_NUM;
158+
n_top += n_vector[n_top_index--];
159+
count -= BC_VECTOR_SIZE;
160+
}
161+
if (count > 0) {
162+
n_top *= BC_POW_10_LUT[count];
163+
n_top += n_vector[n_top_index] / BC_POW_10_LUT[BC_VECTOR_SIZE - count];
164+
}
165+
166+
/* Calculate the initial guess. */
167+
BC_VECTOR initial_guess = bc_fast_sqrt_vector(n_top);
168+
169+
/* Set the obtained initial guess to guess_vector. */
170+
size_t initial_guess_len = (n_top_len_for_initial_guess + 1) / 2;
171+
size_t guess_top_vector_len = guess_full_len % BC_VECTOR_SIZE == 0 ? BC_VECTOR_SIZE : guess_full_len % BC_VECTOR_SIZE;
172+
size_t guess_len_diff = initial_guess_len - guess_top_vector_len;
173+
guess_vector[guess_arr_size - 2] = initial_guess / BC_POW_10_LUT[guess_len_diff];
174+
initial_guess %= BC_POW_10_LUT[guess_len_diff];
175+
guess_vector[guess_arr_size - 3] = initial_guess * BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff];
176+
guess_vector[guess_arr_size - 3] += BC_POW_10_LUT[BC_VECTOR_SIZE - guess_len_diff] - 1;
177+
178+
/* Initialize the uninitialized vector with zeros. */
179+
for (size_t i = 0; i < guess_arr_size - 3; i++) {
180+
guess_vector[i] = 0;
152181
}
153182
guess_vector[guess_arr_size - 1] = 0;
154183

0 commit comments

Comments
 (0)