1 /* Test conversion using mpz_get_str and mpz_set_str.
2
3 Copyright 1993, 1994, 1996, 1999-2002, 2006, 2007, 2020 Free Software
4 Foundation, Inc.
5
6 This file is part of the GNU MP Library test suite.
7
8 The GNU MP Library test suite is free software; you can redistribute it
9 and/or modify it under the terms of the GNU General Public License as
10 published by the Free Software Foundation; either version 3 of the License,
11 or (at your option) any later version.
12
13 The GNU MP Library test suite is distributed in the hope that it will be
14 useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
16 Public License for more details.
17
18 You should have received a copy of the GNU General Public License along with
19 the GNU MP Library test suite. If not, see https://www.gnu.org/licenses/. */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h> /* for strlen */
24 #include <ctype.h> /* for tolower */
25
26 #include "gmp-impl.h"
27 #include "tests.h"
28
29 void debug_mp (mpz_t, int);
30
31 static int str_casecmp (const char *, const char *);
32
33 void
string_urandomb(char * bp,size_t len,int base,gmp_randstate_ptr rands)34 string_urandomb (char *bp, size_t len, int base, gmp_randstate_ptr rands)
35 {
36 mpz_t bs;
37 unsigned long bsi;
38 int d, l;
39 const char *collseq = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz";
40
41 mpz_init (bs);
42
43 mpz_urandomb (bs, rands, 32);
44 bsi = mpz_get_ui (bs);
45 d = bsi % base;
46 while (len != 0)
47 {
48 l = (bsi >> 16) % 20;
49 l = MIN (l, len);
50
51 memset (bp, collseq[d], l);
52
53 len -= l;
54 bp += l;
55
56 mpz_urandomb (bs, rands, 32);
57 bsi = mpz_get_ui (bs);
58 d = bsi & 0xfff;
59 if (d >= base)
60 d = 0;
61 }
62
63 bp[0] = '\0';
64 mpz_clear (bs);
65 }
66
67 int
main(int argc,char ** argv)68 main (int argc, char **argv)
69 {
70 mpz_t op1, op2;
71 mp_size_t size;
72 int i;
73 int reps = 2000;
74 char *str, *buf, *bp;
75 int base;
76 gmp_randstate_ptr rands;
77 mpz_t bs;
78 unsigned long bsi, size_range;
79 size_t len;
80
81 tests_start ();
82 TESTS_REPS (reps, argv, argc);
83
84 rands = RANDS;
85
86 mpz_init (bs);
87
88 mpz_init (op1);
89 mpz_init (op2);
90
91 for (i = 0; i < reps; i++)
92 {
93 /* 1. Generate random mpz_t and convert to a string and back to mpz_t
94 again. */
95 mpz_urandomb (bs, rands, 32);
96 size_range = mpz_get_ui (bs) % 17 + 2; /* 2..18 */
97 mpz_urandomb (bs, rands, size_range); /* 3..262144 bits */
98 size = mpz_get_ui (bs);
99 mpz_rrandomb (op1, rands, size);
100
101 mpz_urandomb (bs, rands, 1);
102 bsi = mpz_get_ui (bs);
103 if ((bsi & 1) != 0)
104 mpz_neg (op1, op1);
105
106 mpz_urandomb (bs, rands, 32);
107 bsi = mpz_get_ui (bs);
108 base = bsi % 62 + 1;
109 if (base == 1)
110 base = 0;
111
112 str = mpz_get_str ((char *) 0, base, op1);
113 mpz_set_str_or_abort (op2, str, base);
114
115 if (mpz_cmp (op1, op2))
116 {
117 fprintf (stderr, "ERROR, op1 and op2 different in test %d\n", i);
118 fprintf (stderr, "str = %s\n", str);
119 fprintf (stderr, "base = %d\n", base);
120 fprintf (stderr, "op1 = "); debug_mp (op1, -16);
121 fprintf (stderr, "op2 = "); debug_mp (op2, -16);
122 abort ();
123 }
124
125 (*__gmp_free_func) (str, strlen (str) + 1);
126
127 /* 2. Generate random string and convert to mpz_t and back to a string
128 again. */
129 mpz_urandomb (bs, rands, 32);
130 size_range = mpz_get_ui (bs) % 16 + 1; /* 1..16 */
131 mpz_urandomb (bs, rands, size_range); /* 1..65536 digits */
132 len = mpz_get_ui (bs) + 1;
133 buf = (char *) (*__gmp_allocate_func) (len + 1);
134 if (base == 0)
135 base = 10;
136 string_urandomb (buf, len, base, rands);
137
138 mpz_set_str_or_abort (op1, buf, base);
139 str = mpz_get_str ((char *) 0, base, op1);
140
141 /* Skip over leading zeros, but don't leave the string at zero length. */
142 for (bp = buf; bp[0] == '0' && bp[1] != '\0'; bp++)
143 ;
144
145 if (str_casecmp (str, bp) != 0)
146 {
147 fprintf (stderr, "ERROR, str and buf different in test %d\n", i);
148 fprintf (stderr, "str = %s\n", str);
149 fprintf (stderr, "buf = %s\n", buf);
150 fprintf (stderr, "base = %d\n", base);
151 fprintf (stderr, "op1 = "); debug_mp (op1, -16);
152 abort ();
153 }
154
155 (*__gmp_free_func) (buf, len + 1);
156 (*__gmp_free_func) (str, strlen (str) + 1);
157 }
158
159 mpz_clear (bs);
160 mpz_clear (op1);
161 mpz_clear (op2);
162
163 tests_end ();
164 exit (0);
165 }
166
167 /* This is similar to POSIX strcasecmp except that we don't do the comparison
168 with unsigned char. We avoid strcasecmp for C standard conformance. */
169 static int
str_casecmp(const char * s1,const char * s2)170 str_casecmp (const char *s1, const char *s2)
171 {
172 size_t i;
173 for (i = 0;; i++)
174 {
175 int c1 = s1[i];
176 int c2 = s2[i];
177 if (c1 == 0 || tolower (c1) != tolower (c2))
178 return c1 - c2;
179 }
180 }
181
182 void
debug_mp(mpz_t x,int base)183 debug_mp (mpz_t x, int base)
184 {
185 mpz_out_str (stderr, base, x); fputc ('\n', stderr);
186 }
187