Skip to content

Commit fc72c8d

Browse files
committed
Efficiently obtain the initial value for the standard path.
1 parent d830c53 commit fc72c8d

File tree

1 file changed

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

1 file changed

+44
-11
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -129,18 +129,51 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
129129

130130
bc_convert_to_vector_with_zero_pad(n_vector, nend, n_full_len, n_extend_zeros);
131131

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

0 commit comments

Comments
 (0)