Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit cbd2aed

Browse files
committedJun 11, 2025
Efficiently obtain the initial value for the standard path.
1 parent 3c74e0f commit cbd2aed

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
@@ -127,18 +127,47 @@ static inline void bc_standard_sqrt(bc_num *num, size_t scale, size_t num_calc_f
127127
const char *nend = (*num)->n_value + leading_zeros + num_use_full_len - 1;
128128
bc_convert_to_vector_with_zero_pad(n_vector, nend, num_use_full_len, num_calc_full_len - num_use_full_len);
129129

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

0 commit comments

Comments
 (0)
Please sign in to comment.