Skip to content

Commit a980339

Browse files
committed
Efficiently obtain the initial value for the standard path.
1 parent 91005a2 commit a980339

File tree

1 file changed

+43
-12
lines changed
  • ext/bcmath/libbcmath/src

1 file changed

+43
-12
lines changed

ext/bcmath/libbcmath/src/sqrt.c

Lines changed: 43 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -133,19 +133,50 @@ static inline void bc_standard_sqrt(bc_num *num, size_t rscale, size_t num_calc_
133133

134134
bc_convert_to_vector_with_zero_pad(n_vector, nend, n_full_len, n_extend_zeros);
135135

136-
/* Prepare guess_vector (Temporary implementation) */
137-
size_t guess_top_len = 0;
138-
for (size_t i = 0; i < guess_arr_size - 2; i++) {
139-
guess_vector[i] = BC_VECTOR_BOUNDARY_NUM - 1;
136+
/* Prepare guess_vector. Use `bc_fast_sqrt_vector()` to quickly obtain a highly accurate initial value. */
137+
138+
/* 18 on 64-bit, 10 on 32-bit */
139+
size_t n_top_len_for_initial_guess = (MAX_LENGTH_OF_LONG - 1) & ~1;
140+
141+
/* Set the number of digits of num to be used as the initial value for Newton's method.
142+
* Just as the square roots of 1000 and 100 differ significantly, the number of digits
143+
* to "ignore" here must be even. */
144+
if (num_calc_full_len & 1) {
145+
#if SIZEOF_SIZE_T == 8
146+
n_top_len_for_initial_guess++; /* 19 */
147+
#else
148+
n_top_len_for_initial_guess--; /* 9 */
149+
#endif
140150
}
141-
if (guess_full_len % BC_VECTOR_SIZE == 0) {
142-
guess_vector[guess_arr_size - 2] = BC_VECTOR_BOUNDARY_NUM - 1;
143-
} else {
144-
guess_vector[guess_arr_size - 2] = 0;
145-
for (size_t i = 0; i < guess_full_len % BC_VECTOR_SIZE; i++) {
146-
guess_vector[guess_arr_size - 2] *= BASE;
147-
guess_vector[guess_arr_size - 2] += 9;
148-
}
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+
177+
/* Initialize the uninitialized vector with zeros. */
178+
for (size_t i = 0; i < guess_arr_size - 3; i++) {
179+
guess_vector[i] = 0;
149180
}
150181
guess_vector[guess_arr_size - 1] = 0;
151182

0 commit comments

Comments
 (0)