@@ -148,6 +148,159 @@ static uint64_t s_time_sqr(int size)
148148 return t1 ;
149149}
150150
151+ /* Set cutoff for radix conversion (base 10 only for now but should be good enough) */
152+ #include <stdlib.h>
153+ static mp_err random_number (char * * string , size_t length )
154+ {
155+ char alphabet [] = "0123456789" , * str_cpy ;
156+
157+ * string = malloc (length + 1 );
158+ if (* string == NULL ) {
159+ return MP_MEM ;
160+ }
161+ str_cpy = * string ;
162+ /* No leading zeros */
163+ do {
164+ * str_cpy = alphabet [rand () % 10 ];
165+ } while (* str_cpy == '0' );
166+ length -- ;
167+ str_cpy ++ ;
168+
169+ do {
170+ * str_cpy = alphabet [rand () % 10 ];
171+ str_cpy ++ ;
172+ } while (-- length > 0 );
173+
174+ * str_cpy = '\0' ;
175+
176+ return MP_OKAY ;
177+ }
178+
179+ #include <string.h>
180+ static uint64_t s_time_radix_conversion_read (int size )
181+ {
182+ int x ;
183+ size_t length ;
184+ size_t written ;
185+ mp_err err ;
186+ mp_int a ;
187+ char * str_a , * str_b ;
188+ uint64_t t1 ;
189+
190+ /* "size" is given as "number of limbs" and starts at 8 */
191+ length = ((size_t )size - 7u ) * MP_DIGIT_BIT ;
192+
193+ /* Over-estimate number of base 10 digits */
194+ /* TODO: can overflow with small INT_MAX */
195+ length = (length * 28u ) / 93u + 2u ;
196+
197+ if ((err = random_number (& str_a , length )) != MP_OKAY ) {
198+ t1 = UINT64_MAX ;
199+ goto LBL_ERR_1 ;
200+ }
201+
202+ if ((err = mp_init (& a )) != MP_OKAY ) {
203+ t1 = UINT64_MAX ;
204+ goto LBL_ERR_2 ;
205+ }
206+ s_timer_start ();
207+ for (x = 0 ; x < s_number_of_test_loops ; x ++ ) {
208+ if ((err = mp_read_radix (& a , str_a , 10 )) != MP_OKAY ) {
209+ t1 = UINT64_MAX ;
210+ goto LBL_ERR_3 ;
211+ }
212+ }
213+ t1 = s_timer_stop ();
214+
215+ if ((err = mp_radix_size (& a , 10 , & length )) != MP_OKAY ) {
216+ t1 = UINT64_MAX ;
217+ goto LBL_ERR_3 ;
218+ }
219+
220+ str_b = malloc (length + 1 );
221+ if (str_b == NULL ) {
222+ t1 = UINT64_MAX ;
223+ goto LBL_ERR_3 ;
224+ }
225+ if ((err = mp_to_radix (& a , str_b , length , & written , 10 )) != MP_OKAY ) {
226+ t1 = UINT64_MAX ;
227+ goto LBL_ERR ;
228+ }
229+
230+ if (strcmp (str_a , str_b ) != 0 ) {
231+ t1 = 0u ;
232+ goto LBL_ERR ;
233+ }
234+
235+ LBL_ERR :
236+ free (str_b );
237+ LBL_ERR_3 :
238+ mp_clear (& a );
239+ LBL_ERR_2 :
240+ free (str_a );
241+ LBL_ERR_1 :
242+ return t1 ;
243+ }
244+
245+ static uint64_t s_time_radix_conversion_write (int size )
246+ {
247+ int x ;
248+ size_t written , length ;
249+ mp_err err ;
250+ mp_int a , b ;
251+ char * str_a ;
252+ uint64_t t1 ;
253+
254+
255+ if ((err = mp_init_multi (& a , & b , NULL )) != MP_OKAY ) {
256+ t1 = UINT64_MAX ;
257+ goto LBL_ERR_1 ;
258+ }
259+ if ((err = mp_rand (& a , size )) != MP_OKAY ) {
260+ t1 = UINT64_MAX ;
261+ goto LBL_ERR_2 ;
262+ }
263+
264+ if ((err = mp_radix_size (& a , 10 , & length )) != MP_OKAY ) {
265+ t1 = UINT64_MAX ;
266+ goto LBL_ERR_2 ;
267+ }
268+
269+ str_a = malloc (length + 1 );
270+ if (str_a == NULL ) {
271+ t1 = UINT64_MAX ;
272+ goto LBL_ERR_2 ;
273+ }
274+
275+ s_timer_start ();
276+ for (x = 0 ; x < s_number_of_test_loops ; x ++ ) {
277+ if ((err = mp_to_radix (& a , str_a , length , & written , 10 )) != MP_OKAY ) {
278+ t1 = UINT64_MAX ;
279+ goto LBL_ERR_2 ;
280+ }
281+ }
282+ t1 = s_timer_stop ();
283+
284+ if ((err = mp_read_radix (& b , str_a , 10 )) != MP_OKAY ) {
285+ t1 = UINT64_MAX ;
286+ goto LBL_ERR ;
287+ }
288+
289+ if (mp_cmp (& a , & b ) != MP_EQ ) {
290+ t1 = 0u ;
291+ goto LBL_ERR ;
292+ }
293+
294+
295+ LBL_ERR :
296+ free (str_a );
297+ LBL_ERR_2 :
298+ mp_clear_multi (& a , & b , NULL );
299+ LBL_ERR_1 :
300+ return t1 ;
301+ }
302+
303+
151304struct tune_args {
152305 int testmode ;
153306 int verbose ;
@@ -238,11 +391,13 @@ static void s_usage(char *s)
238391 fprintf (stderr ," (Not for computing the cut-offs!)\n" );
239392 fprintf (stderr ," -s 'preset' use values in 'preset' for printing.\n" );
240393 fprintf (stderr ," 'preset' is a comma separated string with cut-offs for\n" );
241- fprintf (stderr ," ksm, kss, tc3m, tc3s in that order\n" );
394+ fprintf (stderr ," ksm, kss, tc3m, tc3s, rcr, rcw in that order\n" );
242395 fprintf (stderr ," ksm = karatsuba multiplication\n" );
243396 fprintf (stderr ," kss = karatsuba squaring\n" );
244397 fprintf (stderr ," tc3m = Toom-Cook 3-way multiplication\n" );
245398 fprintf (stderr ," tc3s = Toom-Cook 3-way squaring\n" );
399+ fprintf (stderr ," rcr = Fast radix conversion, reading\n" );
400+ fprintf (stderr ," rcw = Fast radix conversion, writing\n" );
246401 fprintf (stderr ," Implies '-p'\n" );
247402 fprintf (stderr ," -h this message\n" );
248403 exit (s_exit_code );
@@ -251,17 +406,20 @@ static void s_usage(char *s)
251406struct cutoffs {
252407 int MUL_KARATSUBA , SQR_KARATSUBA ;
253408 int MUL_TOOM , SQR_TOOM ;
409+ int RADIX_READ , RADIX_WRITE ;
254410};
255411
256412const struct cutoffs max_cutoffs =
257- { INT_MAX , INT_MAX , INT_MAX , INT_MAX };
413+ { INT_MAX , INT_MAX , INT_MAX , INT_MAX , INT_MAX , INT_MAX };
258414
259415static void set_cutoffs (const struct cutoffs * c )
260416{
261417 MP_MUL_KARATSUBA_CUTOFF = c -> MUL_KARATSUBA ;
262418 MP_SQR_KARATSUBA_CUTOFF = c -> SQR_KARATSUBA ;
263419 MP_MUL_TOOM_CUTOFF = c -> MUL_TOOM ;
264420 MP_SQR_TOOM_CUTOFF = c -> SQR_TOOM ;
421+ MP_RADIX_READ_CUTOFF = c -> RADIX_READ ;
422+ MP_RADIX_WRITE_CUTOFF = c -> RADIX_WRITE ;
265423}
266424
267425static void get_cutoffs (struct cutoffs * c )
@@ -270,7 +428,8 @@ static void get_cutoffs(struct cutoffs *c)
270428 c -> SQR_KARATSUBA = MP_SQR_KARATSUBA_CUTOFF ;
271429 c -> MUL_TOOM = MP_MUL_TOOM_CUTOFF ;
272430 c -> SQR_TOOM = MP_SQR_TOOM_CUTOFF ;
273-
431+ c -> RADIX_READ = MP_RADIX_READ_CUTOFF ;
432+ c -> RADIX_WRITE = MP_RADIX_WRITE_CUTOFF ;
274433}
275434
276435int main (int argc , char * * argv )
@@ -416,13 +575,17 @@ int main(int argc, char **argv)
416575 s_usage (argv [0 ]);
417576 }
418577 str = argv [opt ];
419- MP_MUL_KARATSUBA_CUTOFF = (int )s_strtol (str , & endptr , "[1/4] No value for MP_MUL_KARATSUBA_CUTOFF given" );
578+ MP_MUL_KARATSUBA_CUTOFF = (int )s_strtol (str , & endptr , "[1/6] No value for MP_MUL_KARATSUBA_CUTOFF given" );
579+ str = endptr + 1 ;
580+ MP_SQR_KARATSUBA_CUTOFF = (int )s_strtol (str , & endptr , "[2/6] No value for MP_SQR_KARATSUBA_CUTOFF given" );
420581 str = endptr + 1 ;
421- MP_SQR_KARATSUBA_CUTOFF = (int )s_strtol (str , & endptr , "[2/4 ] No value for MP_SQR_KARATSUBA_CUTOFF given" );
582+ MP_MUL_TOOM_CUTOFF = (int )s_strtol (str , & endptr , "[3/6 ] No value for MP_MUL_TOOM_CUTOFF given" );
422583 str = endptr + 1 ;
423- MP_MUL_TOOM_CUTOFF = (int )s_strtol (str , & endptr , "[3/4 ] No value for MP_MUL_TOOM_CUTOFF given" );
584+ MP_SQR_TOOM_CUTOFF = (int )s_strtol (str , & endptr , "[4/6 ] No value for MP_SQR_TOOM_CUTOFF given" );
424585 str = endptr + 1 ;
425- MP_SQR_TOOM_CUTOFF = (int )s_strtol (str , & endptr , "[4/4] No value for MP_SQR_TOOM_CUTOFF given" );
586+ MP_RADIX_READ_CUTOFF = (int )s_strtol (str , & endptr , "[5/6] No value for MP_RADIX_READ_CUTOFF given" );
587+ str = endptr + 1 ;
588+ MP_RADIX_WRITE_CUTOFF = (int )s_strtol (str , & endptr , "[6/6] No value for MP_RADIX_WRITE_CUTOFF given" );
426589 break ;
427590 case 'h' :
428591 s_exit_code = EXIT_SUCCESS ;
@@ -461,31 +624,54 @@ int main(int argc, char **argv)
461624 T_MUL_SQR ("Karatsuba squaring" , SQR_KARATSUBA , s_time_sqr ),
462625 T_MUL_SQR ("Toom-Cook 3-way multiplying" , MUL_TOOM , s_time_mul ),
463626 T_MUL_SQR ("Toom-Cook 3-way squaring" , SQR_TOOM , s_time_sqr ),
627+ /* TODO: adapt macro above (or the names of the cutoffs and/or functions) */
628+ {
629+ "\"Faster radix conversion (reading)\"" , & MP_RADIX_READ_CUTOFF ,
630+ & (updated .RADIX_READ ),MP_HAS (S_MP_FASTER_READ_RADIX ) ? s_time_radix_conversion_read : NULL
631+ },
632+ {
633+ "\"Faster radix conversion (writing)\"" , & MP_RADIX_WRITE_CUTOFF ,
634+ & (updated .RADIX_WRITE ),MP_HAS (S_MP_FASTER_TO_RADIX ) ? s_time_radix_conversion_write : NULL
635+ }
464636#undef T_MUL_SQR
465637 };
466638 /* Turn all limits from bncore.c to the max */
467639 set_cutoffs (& max_cutoffs );
468- for (n = 0 ; n < sizeof (test )/sizeof (test [0 ]); ++ n ) {
640+ for (n = 0 ; n < ( sizeof (test )/sizeof (test [0 ]) - 2 ); ++ n ) {
469641 if (test [n ].fn != NULL ) {
470642 s_run (test [n ].name , test [n ].fn , test [n ].cutoff );
471643 * test [n ].update = * test [n ].cutoff ;
472644 * test [n ].cutoff = INT_MAX ;
645+ };
646+ }
647+ /* Cutoffs for radix conversions are in bits to make handling of 62 different radices
648+ more feasible. */
649+ for (; n < sizeof (test )/sizeof (test [0 ]); ++ n ) {
650+ if (test [n ].fn != NULL ) {
651+ s_run (test [n ].name , test [n ].fn , test [n ].cutoff );
652+ /* TODO: can overflow for small INT_MAX */
653+ * test [n ].update = ((* test [n ].cutoff ) * MP_DIGIT_BIT * 93 )/28 ;
654+ * test [n ].cutoff = INT_MAX ;
473655 }
474656 }
475657 }
476658 if (args .terse == 1 ) {
477- printf ("%d %d %d %d\n" ,
659+ printf ("%d %d %d %d %d %d \n" ,
478660 updated .MUL_KARATSUBA ,
479661 updated .SQR_KARATSUBA ,
480662 updated .MUL_TOOM ,
481- updated .SQR_TOOM );
663+ updated .SQR_TOOM ,
664+ updated .RADIX_READ ,
665+ updated .RADIX_WRITE );
482666 } else {
483667 printf ("MUL_KARATSUBA_CUTOFF = %d\n" , updated .MUL_KARATSUBA );
484668 printf ("SQR_KARATSUBA_CUTOFF = %d\n" , updated .SQR_KARATSUBA );
485669 printf ("MUL_TOOM_CUTOFF = %d\n" , updated .MUL_TOOM );
486670 printf ("SQR_TOOM_CUTOFF = %d\n" , updated .SQR_TOOM );
671+ printf ("RADIX_READ_CUTOFF = %d\n" , updated .RADIX_READ );
672+ printf ("RADIX_WRITE_CUTOFF = %d\n" , updated .RADIX_WRITE );
487673 }
488-
674+ /* TODO: add graphs for radix conversion, too? */
489675 if (args .print == 1 ) {
490676 printf ("Printing data for graphing to \"%s\" and \"%s\"\n" ,mullog , sqrlog );
491677
0 commit comments