3030*************************************************************************/
3131
3232#include "bcmath.h"
33+ #include "convert.h"
34+ #include "private.h"
3335#include <assert.h>
3436#include <stdbool.h>
3537#include <stddef.h>
3638
37- void bc_square_ex (bc_num n1 , bc_num * result , size_t scale_min ) {
38- bc_num square_ex = bc_square (n1 , scale_min );
39- bc_free_num (result );
40- * (result ) = square_ex ;
39+ static size_t bc_multiply_vector_ex (
40+ BC_VECTOR * * n1_vector , size_t n1_arr_size , BC_VECTOR * n2_vector , size_t n2_arr_size , BC_VECTOR * * result_vector )
41+ {
42+ size_t result_arr_size = n1_arr_size + n2_arr_size ;
43+ bc_multiply_vector (* n1_vector , n1_arr_size , n2_vector , n2_arr_size , * result_vector , result_arr_size );
44+
45+ /* Eliminate extra zeros because they increase the number of calculations. */
46+ while ((* result_vector )[result_arr_size - 1 ] == 0 ) {
47+ result_arr_size -- ;
48+ }
49+
50+ /* Swap n1_vector and result_vector. */
51+ BC_VECTOR * tmp = * n1_vector ;
52+ * n1_vector = * result_vector ;
53+ * result_vector = tmp ;
54+
55+ return result_arr_size ;
56+ }
57+
58+ #define bc_square_vector_ex (bvec , bsize , rvec ) bc_multiply_vector_ex((bvec), (bsize), (*bvec), (bsize), (rvec))
59+
60+ /* Use "exponentiation by squaring". This is the fast path when the results are small. */
61+ static inline bc_num bc_fast_raise (
62+ const char * base_end , long exponent , size_t base_len , size_t power_len , size_t power_scale , size_t power_full_len )
63+ {
64+ BC_VECTOR base_vector = 0 ;
65+
66+ /* Convert to BC_VECTOR[] */
67+ bc_convert_to_vector (& base_vector , base_end , base_len );
68+
69+ while ((exponent & 1 ) == 0 ) {
70+ base_vector *= base_vector ;
71+ exponent >>= 1 ;
72+ }
73+
74+ /* copy base to power */
75+ BC_VECTOR power_vector = base_vector ;
76+ exponent >>= 1 ;
77+
78+ while (exponent > 0 ) {
79+ base_vector *= base_vector ;
80+ if ((exponent & 1 ) == 1 ) {
81+ power_vector *= base_vector ;
82+ }
83+ exponent >>= 1 ;
84+ }
85+
86+ bc_num power = bc_new_num_nonzeroed (power_len , power_scale );
87+ char * pptr = power -> n_value ;
88+ char * pend = pptr + power_full_len - 1 ;
89+
90+ while (pend >= pptr ) {
91+ * pend -- = power_vector % BASE ;
92+ power_vector /= BASE ;
93+ }
94+ return power ;
95+ }
96+
97+ /* Use "exponentiation by squaring". This is the standard path. */
98+ static bc_num bc_standard_raise (
99+ const char * base_ptr , const char * base_end , long exponent , size_t base_len , size_t power_scale )
100+ {
101+ /* Remove the leading zeros as they will be filled in later. */
102+ while (* base_ptr ++ == 0 ) {
103+ base_len -- ;
104+ }
105+
106+ size_t base_arr_size = BC_ARR_SIZE_FROM_LEN (base_len );
107+ size_t max_power_arr_size = base_arr_size * exponent ;
108+
109+ /* The allocated memory area is reused on a rotational basis, so the same size is required. */
110+ BC_VECTOR * buf = safe_emalloc (max_power_arr_size * 3 , sizeof (BC_VECTOR ), 0 );
111+ BC_VECTOR * base_vector = buf ;
112+ BC_VECTOR * power_vector = base_vector + max_power_arr_size ;
113+ BC_VECTOR * tmp_result_vector = power_vector + max_power_arr_size ;
114+
115+ /* Convert to BC_VECTOR[] */
116+ bc_convert_to_vector (base_vector , base_end , base_len );
117+
118+ while ((exponent & 1 ) == 0 ) {
119+ base_arr_size = bc_square_vector_ex (& base_vector , base_arr_size , & tmp_result_vector );
120+ exponent >>= 1 ;
121+ }
122+
123+ /* copy base to power */
124+ size_t power_arr_size = base_arr_size ;
125+ for (size_t i = 0 ; i < base_arr_size ; i ++ ) {
126+ power_vector [i ] = base_vector [i ];
127+ }
128+ exponent >>= 1 ;
129+
130+ while (exponent > 0 ) {
131+ base_arr_size = bc_square_vector_ex (& base_vector , base_arr_size , & tmp_result_vector );
132+ if ((exponent & 1 ) == 1 ) {
133+ power_arr_size = bc_multiply_vector_ex (& power_vector , power_arr_size , base_vector , base_arr_size , & tmp_result_vector );
134+ }
135+ exponent >>= 1 ;
136+ }
137+
138+ /* Convert to bc_num */
139+ size_t power_leading_zeros = 0 ;
140+ size_t power_len ;
141+ size_t power_full_len = power_arr_size * BC_VECTOR_SIZE ;
142+ if (power_full_len > power_scale ) {
143+ power_len = power_full_len - power_scale ;
144+ } else {
145+ power_len = 1 ;
146+ power_leading_zeros = power_scale - power_full_len + 1 ;
147+ power_full_len = power_scale + 1 ;
148+ }
149+ bc_num power = bc_new_num_nonzeroed (power_len , power_scale );
150+
151+ char * pptr = power -> n_value ;
152+ char * pend = pptr + power_full_len - 1 ;
153+
154+ /* Pad with leading zeros if necessary. */
155+ while (power_leading_zeros > sizeof (uint32_t )) {
156+ bc_write_bcd_representation (0 , pptr );
157+ pptr += sizeof (uint32_t );
158+ power_leading_zeros -= sizeof (uint32_t );
159+ }
160+ for (size_t i = 0 ; i < power_leading_zeros ; i ++ ) {
161+ * pptr ++ = 0 ;
162+ }
163+
164+ bc_convert_vector_to_char (power_vector , pptr , pend , power_arr_size );
165+
166+ efree (buf );
167+
168+ return power ;
41169}
42170
43171/* Raise "base" to the "exponent" power. The result is placed in RESULT.
44172 Maximum exponent is LONG_MAX. If a "exponent" is not an integer,
45173 only the integer part is used. */
46174bool bc_raise (bc_num base , long exponent , bc_num * result , size_t scale ) {
47- bc_num temp , power ;
48175 size_t rscale ;
49- size_t pwrscale ;
50- size_t calcscale ;
51176 bool is_neg ;
52177
53178 /* Special case if exponent is a zero. */
@@ -74,43 +199,47 @@ bool bc_raise(bc_num base, long exponent, bc_num *result, size_t scale) {
74199 return !is_neg ;
75200 }
76201
77- /* Set initial value of temp. */
78- power = bc_copy_num (base );
79- pwrscale = base -> n_scale ;
80- while ((exponent & 1 ) == 0 ) {
81- pwrscale = 2 * pwrscale ;
82- bc_square_ex (power , & power , pwrscale );
83- exponent = exponent >> 1 ;
202+ size_t base_len = base -> n_len + base -> n_scale ;
203+ size_t power_len = base -> n_len * exponent ;
204+ size_t power_scale = base -> n_scale * exponent ;
205+ size_t power_full_len = power_len + power_scale ;
206+
207+ sign power_sign ;
208+ if (base -> n_sign == MINUS && (exponent & 1 ) == 1 ) {
209+ power_sign = MINUS ;
210+ } else {
211+ power_sign = PLUS ;
84212 }
85- temp = bc_copy_num (power );
86- calcscale = pwrscale ;
87- exponent = exponent >> 1 ;
88213
89- /* Do the calculation. */
90- while (exponent > 0 ) {
91- pwrscale = 2 * pwrscale ;
92- bc_square_ex (power , & power , pwrscale );
93- if ((exponent & 1 ) == 1 ) {
94- calcscale = pwrscale + calcscale ;
95- bc_multiply_ex (temp , power , & temp , calcscale );
96- }
97- exponent = exponent >> 1 ;
214+ const char * base_end = base -> n_value + base_len - 1 ;
215+
216+ bc_num power ;
217+ if (base_len <= BC_VECTOR_SIZE && power_full_len <= BC_VECTOR_SIZE * 2 ) {
218+ power = bc_fast_raise (base_end , exponent , base_len , power_len , power_scale , power_full_len );
219+ } else {
220+ power = bc_standard_raise (base -> n_value , base_end , exponent , base_len , power_scale );
221+ }
222+
223+ _bc_rm_leading_zeros (power );
224+ if (bc_is_zero (power )) {
225+ power -> n_sign = PLUS ;
226+ power -> n_scale = 0 ;
227+ } else {
228+ power -> n_sign = power_sign ;
98229 }
99230
100231 /* Assign the value. */
101232 if (is_neg ) {
102- if (bc_divide (BCG (_one_ ), temp , result , rscale ) == false) {
103- bc_free_num (& temp );
233+ if (bc_divide (BCG (_one_ ), power , result , rscale ) == false) {
104234 bc_free_num (& power );
105235 return false;
106236 }
107- bc_free_num (& temp );
237+ bc_free_num (& power );
108238 } else {
109239 bc_free_num (result );
110- * result = temp ;
240+ * result = power ;
111241 (* result )-> n_scale = MIN (scale , (* result )-> n_scale );
112242 }
113- bc_free_num (& power );
114243 return true;
115244}
116245
0 commit comments