30
30
*************************************************************************/
31
31
32
32
#include "bcmath.h"
33
+ #include "convert.h"
34
+ #include "private.h"
33
35
#include <assert.h>
34
36
#include <stdbool.h>
35
37
#include <stddef.h>
36
38
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 inline 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
+ static inline size_t bc_square_vector_ex (BC_VECTOR * * base_vector , size_t base_arr_size , BC_VECTOR * * result_vector )
59
+ {
60
+ return bc_multiply_vector_ex (base_vector , base_arr_size , * base_vector , base_arr_size , result_vector );
61
+ }
62
+
63
+ /* Use "exponentiation by squaring". This is the fast path when the results are small. */
64
+ static inline bc_num bc_fast_raise (
65
+ const char * base_end , long exponent , size_t base_len , size_t power_len , size_t power_scale , size_t power_full_len )
66
+ {
67
+ BC_VECTOR base_vector = 0 ;
68
+
69
+ /* Convert to BC_VECTOR[] */
70
+ bc_convert_to_vector (& base_vector , base_end , base_len );
71
+
72
+ while ((exponent & 1 ) == 0 ) {
73
+ base_vector *= base_vector ;
74
+ exponent >>= 1 ;
75
+ }
76
+
77
+ /* copy base to power */
78
+ BC_VECTOR power_vector = base_vector ;
79
+ exponent >>= 1 ;
80
+
81
+ while (exponent > 0 ) {
82
+ base_vector *= base_vector ;
83
+ if ((exponent & 1 ) == 1 ) {
84
+ power_vector *= base_vector ;
85
+ }
86
+ exponent >>= 1 ;
87
+ }
88
+
89
+ bc_num power = bc_new_num_nonzeroed (power_len , power_scale );
90
+ char * pptr = power -> n_value ;
91
+ char * pend = pptr + power_full_len - 1 ;
92
+
93
+ while (pend >= pptr ) {
94
+ * pend -- = power_vector % BASE ;
95
+ power_vector /= BASE ;
96
+ }
97
+ return power ;
98
+ }
99
+
100
+ /* Use "exponentiation by squaring". This is the standard path. */
101
+ static bc_num bc_standard_raise (
102
+ const char * base_ptr , const char * base_end , long exponent , size_t base_len , size_t power_scale )
103
+ {
104
+ /* Remove the leading zeros as they will be filled in later. */
105
+ while (* base_ptr ++ == 0 ) {
106
+ base_len -- ;
107
+ }
108
+
109
+ size_t base_arr_size = (base_len + BC_VECTOR_SIZE - 1 ) / BC_VECTOR_SIZE ;
110
+ size_t max_power_arr_size = base_arr_size * exponent ;
111
+
112
+ /* The allocated memory area is reused on a rotational basis, so the same size is required. */
113
+ BC_VECTOR * buf = safe_emalloc (max_power_arr_size * 3 , sizeof (BC_VECTOR ), 0 );
114
+ BC_VECTOR * base_vector = buf ;
115
+ BC_VECTOR * power_vector = base_vector + max_power_arr_size ;
116
+ BC_VECTOR * tmp_result_vector = power_vector + max_power_arr_size ;
117
+
118
+ /* Convert to BC_VECTOR[] */
119
+ bc_convert_to_vector (base_vector , base_end , base_len );
120
+
121
+ while ((exponent & 1 ) == 0 ) {
122
+ base_arr_size = bc_square_vector_ex (& base_vector , base_arr_size , & tmp_result_vector );
123
+ exponent >>= 1 ;
124
+ }
125
+
126
+ /* copy base to power */
127
+ size_t power_arr_size = base_arr_size ;
128
+ for (size_t i = 0 ; i < base_arr_size ; i ++ ) {
129
+ power_vector [i ] = base_vector [i ];
130
+ }
131
+ exponent >>= 1 ;
132
+
133
+ while (exponent > 0 ) {
134
+ base_arr_size = bc_square_vector_ex (& base_vector , base_arr_size , & tmp_result_vector );
135
+ if ((exponent & 1 ) == 1 ) {
136
+ power_arr_size = bc_multiply_vector_ex (& power_vector , power_arr_size , base_vector , base_arr_size , & tmp_result_vector );
137
+ }
138
+ exponent >>= 1 ;
139
+ }
140
+
141
+ /* Convert to bc_num */
142
+ size_t power_leading_zeros = 0 ;
143
+ size_t power_len ;
144
+ size_t power_full_len = power_arr_size * BC_VECTOR_SIZE ;
145
+ if (power_full_len > power_scale ) {
146
+ power_len = power_full_len - power_scale ;
147
+ } else {
148
+ power_len = 1 ;
149
+ power_leading_zeros = power_scale - power_full_len + 1 ;
150
+ power_full_len = power_scale + 1 ;
151
+ }
152
+ bc_num power = bc_new_num_nonzeroed (power_len , power_scale );
153
+
154
+ char * pptr = power -> n_value ;
155
+ char * pend = pptr + power_full_len - 1 ;
156
+
157
+ /* Pad with leading zeros if necessary. */
158
+ while (power_leading_zeros > sizeof (uint32_t )) {
159
+ bc_write_bcd_representation (0 , pptr );
160
+ pptr += sizeof (uint32_t );
161
+ power_leading_zeros -= sizeof (uint32_t );
162
+ }
163
+ for (size_t i = 0 ; i < power_leading_zeros ; i ++ ) {
164
+ * pptr ++ = 0 ;
165
+ }
166
+
167
+ size_t i = 0 ;
168
+ while (i < power_arr_size - 1 ) {
169
+ #if BC_VECTOR_SIZE == 4
170
+ bc_write_bcd_representation (power_vector [i ], pend - 3 );
171
+ pend -= 4 ;
172
+ #else
173
+ bc_write_bcd_representation (power_vector [i ] / 10000 , pend - 7 );
174
+ bc_write_bcd_representation (power_vector [i ] % 10000 , pend - 3 );
175
+ pend -= 8 ;
176
+ #endif
177
+ i ++ ;
178
+ }
179
+
180
+ while (pend >= pptr ) {
181
+ * pend -- = power_vector [i ] % BASE ;
182
+ power_vector [i ] /= BASE ;
183
+ }
184
+
185
+ efree (buf );
186
+
187
+ return power ;
41
188
}
42
189
43
190
/* Raise "base" to the "exponent" power. The result is placed in RESULT.
44
191
Maximum exponent is LONG_MAX. If a "exponent" is not an integer,
45
192
only the integer part is used. */
46
193
bool bc_raise (bc_num base , long exponent , bc_num * result , size_t scale ) {
47
- bc_num temp , power ;
48
194
size_t rscale ;
49
- size_t pwrscale ;
50
- size_t calcscale ;
51
195
bool is_neg ;
52
196
53
197
/* Special case if exponent is a zero. */
@@ -74,43 +218,47 @@ bool bc_raise(bc_num base, long exponent, bc_num *result, size_t scale) {
74
218
return !is_neg ;
75
219
}
76
220
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 ;
221
+ size_t base_len = base -> n_len + base -> n_scale ;
222
+ size_t power_len = base -> n_len * exponent ;
223
+ size_t power_scale = base -> n_scale * exponent ;
224
+ size_t power_full_len = power_len + power_scale ;
225
+
226
+ sign power_sign ;
227
+ if (base -> n_sign == MINUS && (exponent & 1 ) == 1 ) {
228
+ power_sign = MINUS ;
229
+ } else {
230
+ power_sign = PLUS ;
84
231
}
85
- temp = bc_copy_num (power );
86
- calcscale = pwrscale ;
87
- exponent = exponent >> 1 ;
88
232
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 ;
233
+ const char * base_end = base -> n_value + base_len - 1 ;
234
+
235
+ bc_num power ;
236
+ if (base_len <= BC_VECTOR_SIZE && power_full_len <= BC_VECTOR_SIZE * 2 ) {
237
+ power = bc_fast_raise (base_end , exponent , base_len , power_len , power_scale , power_full_len );
238
+ } else {
239
+ power = bc_standard_raise (base -> n_value , base_end , exponent , base_len , power_scale );
240
+ }
241
+
242
+ _bc_rm_leading_zeros (power );
243
+ if (bc_is_zero (power )) {
244
+ power -> n_sign = PLUS ;
245
+ power -> n_scale = 0 ;
246
+ } else {
247
+ power -> n_sign = power_sign ;
98
248
}
99
249
100
250
/* Assign the value. */
101
251
if (is_neg ) {
102
- if (bc_divide (BCG (_one_ ), temp , result , rscale ) == false) {
103
- bc_free_num (& temp );
252
+ if (bc_divide (BCG (_one_ ), power , result , rscale ) == false) {
104
253
bc_free_num (& power );
105
254
return false;
106
255
}
107
- bc_free_num (& temp );
256
+ bc_free_num (& power );
108
257
} else {
109
258
bc_free_num (result );
110
- * result = temp ;
259
+ * result = power ;
111
260
(* result )-> n_scale = MIN (scale , (* result )-> n_scale );
112
261
}
113
- bc_free_num (& power );
114
262
return true;
115
263
}
116
264
0 commit comments