@@ -112,6 +112,52 @@ static inline void bc_fast_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len,
112
112
}
113
113
}
114
114
115
+ #if BC_LITTLE_ENDIAN
116
+ # define BC_ENCODE_LUT (A , B ) ((A) | (B) << 4)
117
+ #else
118
+ # define BC_ENCODE_LUT (A , B ) ((B) | (A) << 4)
119
+ #endif
120
+
121
+ #define LUT_ITERATE (_ , A ) \
122
+ _(A, 0), _(A, 1), _(A, 2), _(A, 3), _(A, 4), _(A, 5), _(A, 6), _(A, 7), _(A, 8), _(A, 9)
123
+
124
+ /* This LUT encodes the decimal representation of numbers 0-100
125
+ * such that we can avoid taking modulos and divisions which would be slow. */
126
+ static const unsigned char LUT [100 ] = {
127
+ LUT_ITERATE (BC_ENCODE_LUT , 0 ),
128
+ LUT_ITERATE (BC_ENCODE_LUT , 1 ),
129
+ LUT_ITERATE (BC_ENCODE_LUT , 2 ),
130
+ LUT_ITERATE (BC_ENCODE_LUT , 3 ),
131
+ LUT_ITERATE (BC_ENCODE_LUT , 4 ),
132
+ LUT_ITERATE (BC_ENCODE_LUT , 5 ),
133
+ LUT_ITERATE (BC_ENCODE_LUT , 6 ),
134
+ LUT_ITERATE (BC_ENCODE_LUT , 7 ),
135
+ LUT_ITERATE (BC_ENCODE_LUT , 8 ),
136
+ LUT_ITERATE (BC_ENCODE_LUT , 9 ),
137
+ };
138
+
139
+ static inline unsigned short bc_expand_lut (unsigned char c )
140
+ {
141
+ return (c & 0x0f ) | (c & 0xf0 ) << 4 ;
142
+ }
143
+
144
+ /* Writes the character representation of the number encoded in value.
145
+ * E.g. if value = 1234, then the string "1234" will be written to str. */
146
+ static void bc_write_bcd_representation (uint32_t value , char * str )
147
+ {
148
+ uint32_t upper = value / 100 ; /* e.g. 12 */
149
+ uint32_t lower = value % 100 ; /* e.g. 34 */
150
+
151
+ #if BC_LITTLE_ENDIAN
152
+ /* Note: little endian, so `lower` comes before `upper`! */
153
+ uint32_t digits = bc_expand_lut (LUT [lower ]) << 16 | bc_expand_lut (LUT [upper ]);
154
+ #else
155
+ /* Note: big endian, so `upper` comes before `lower`! */
156
+ uint32_t digits = bc_expand_lut (LUT [upper ]) << 16 | bc_expand_lut (LUT [lower ]);
157
+ #endif
158
+ memcpy (str , & digits , sizeof (digits ));
159
+ }
160
+
115
161
/*
116
162
* Converts the BCD of bc_num by 4 (32 bits) or 8 (64 bits) digits to an array of BC_UINT_Ts.
117
163
* The array is generated starting with the smaller digits.
@@ -180,9 +226,13 @@ static void bc_standard_mul(bc_num n1, size_t n1len, bc_num n2, size_t n2len, bc
180
226
char * pend = pptr + prodlen - 1 ;
181
227
i = 0 ;
182
228
while (i < prod_arr_size - 1 ) {
183
- for (size_t j = 0 ; j < BC_MUL_UINT_DIGITS ; j ++ ) {
184
- * pend -- = prod_uint [i ] % BASE ;
185
- prod_uint [i ] /= BASE ;
229
+ if (BC_MUL_UINT_DIGITS == 4 ) {
230
+ bc_write_bcd_representation (prod_uint [i ], pend - 3 );
231
+ pend -= 4 ;
232
+ } else {
233
+ bc_write_bcd_representation (prod_uint [i ] / 10000 , pend - 7 );
234
+ bc_write_bcd_representation (prod_uint [i ] % 10000 , pend - 3 );
235
+ pend -= 8 ;
186
236
}
187
237
i ++ ;
188
238
}
0 commit comments