1/* Test ostream formatted output.
2
3Copyright 2001, 2002 Free Software Foundation, Inc.
4
5This file is part of the GNU MP Library.
6
7The GNU MP Library is free software; you can redistribute it and/or modify
8it under the terms of the GNU Lesser General Public License as published by
9the Free Software Foundation; either version 3 of the License, or (at your
10option) any later version.
11
12The GNU MP Library is distributed in the hope that it will be useful, but
13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
14or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public
15License for more details.
16
17You should have received a copy of the GNU Lesser General Public License
18along with the GNU MP Library.  If not, see http://www.gnu.org/licenses/.  */
19
20#include <iostream>
21#include <cstdlib>
22
23#include "gmp.h"
24#include "gmp-impl.h"
25#include "tests.h"
26
27using namespace std;
28
29
30int   option_check_standard = 0;
31
32
33#define CALL(expr)							\
34  do {									\
35    got.flags (data[i].flags);						\
36    got.width (data[i].width);						\
37    got.precision (data[i].precision);					\
38    if (data[i].fill == '\0')						\
39      got.fill (' ');							\
40    else								\
41      got.fill (data[i].fill);						\
42									\
43    if (! (expr))							\
44      {									\
45	cout << "\"got\" output error\n";				\
46	abort ();							\
47      }									\
48    if (got.width() != 0)						\
49      {									\
50	cout << "\"got\" width not reset to 0\n";			\
51	abort ();							\
52      }									\
53									\
54  } while (0)
55
56
57#define DUMP()								\
58  do {									\
59    cout << "  want:  |" << data[i].want << "|\n";			\
60    cout << "  got:   |" << got.str() << "|\n";				\
61    cout << "  width: " << data[i].width << "\n";			\
62    cout << "  prec:  " << got.precision() << "\n";			\
63    cout << "  flags: " << hex << (unsigned long) got.flags() << "\n";	\
64  } while (0)
65
66#define ABORT() \
67  do {          \
68    DUMP ();    \
69    abort ();   \
70  } while (0)
71
72void
73check_mpz (void)
74{
75  static const struct {
76    const char     *z;
77    const char     *want;
78    ios::fmtflags  flags;
79    int            width;
80    int            precision;
81    char           fill;
82
83  } data[] = {
84
85    { "0", "0", ios::dec },
86
87    { "0", "0", ios::oct },
88    { "0", "0", ios::oct | ios::showbase },
89
90    { "0", "0", ios::hex },
91    { "0", "0x0", ios::hex | ios::showbase },
92    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
93
94    { "1", "****1", ios::dec, 5, 0, '*' },
95
96    { "-1", "   -1",  ios::dec | ios::right,    5 },
97    { "-1", "-   1",  ios::dec | ios::internal, 5 },
98    { "-1", "-1   ",  ios::dec | ios::left,     5 },
99
100    { "1", "   0x1", ios::hex | ios::showbase | ios::right,    6 },
101    { "1", "0x   1", ios::hex | ios::showbase | ios::internal, 6 },
102    { "1", "0x1   ", ios::hex | ios::showbase | ios::left,     6 },
103
104    { "1", "   +0x1", ios::hex | ios::showbase | ios::showpos | ios::right,
105      7 },
106    { "1", "+0x   1", ios::hex | ios::showbase | ios::showpos | ios::internal,
107      7 },
108    { "1", "+0x1   ", ios::hex | ios::showbase | ios::showpos | ios::left,
109      7 },
110
111    {  "123",    "7b", ios::hex },
112    {  "123",    "7B", ios::hex | ios::uppercase },
113    {  "123",  "0x7b", ios::hex | ios::showbase },
114    {  "123",  "0X7B", ios::hex | ios::showbase | ios::uppercase },
115    { "-123", "-0x7b", ios::hex | ios::showbase },
116    { "-123", "-0X7B", ios::hex | ios::showbase | ios::uppercase },
117
118    {  "123",   "173", ios::oct },
119    {  "123",   "173", ios::oct | ios::uppercase },
120    {  "123",  "0173", ios::oct | ios::showbase },
121    {  "123",  "0173", ios::oct | ios::showbase | ios::uppercase },
122    { "-123", "-0173", ios::oct | ios::showbase },
123    { "-123", "-0173", ios::oct | ios::showbase | ios::uppercase },
124
125  };
126
127  size_t  i;
128  mpz_t   z;
129
130  mpz_init (z);
131
132  for (i = 0; i < numberof (data); i++)
133    {
134      mpz_set_str_or_abort (z, data[i].z, 0);
135
136      if (option_check_standard
137	  && mpz_fits_slong_p (z)
138
139	  // no negatives or showpos in hex or oct
140	  && (((data[i].flags & ios::basefield) == ios::hex
141	       || (data[i].flags & ios::basefield) == ios::oct)
142	      ? (mpz_sgn (z) >= 0
143		 && ! (data[i].flags & ios::showpos))
144	      : 1)
145	  )
146	{
147	  ostringstream  got;
148	  long  n = mpz_get_si (z);
149	  CALL (got << n);
150	  if (got.str().compare (data[i].want) != 0)
151	    {
152	      cout << "check_mpz data[" << i
153		   << "] doesn't match standard ostream output\n";
154	      cout << "  z:     " << data[i].z << "\n";
155	      cout << "  n:     " << n << "\n";
156	      DUMP ();
157	    }
158	}
159
160      {
161	ostringstream  got;
162	CALL (got << z);
163	if (got.str().compare (data[i].want) != 0)
164	  {
165	    cout << "mpz operator<< wrong, data[" << i << "]\n";
166	    cout << "  z:     " << data[i].z << "\n";
167	    ABORT ();
168	  }
169      }
170    }
171
172  mpz_clear (z);
173}
174
175void
176check_mpq (void)
177{
178  static const struct {
179    const char     *q;
180    const char     *want;
181    ios::fmtflags  flags;
182    int            width;
183    int            precision;
184    char           fill;
185
186  } data[] = {
187
188    { "0", "0", ios::dec },
189    { "0", "0", ios::hex },
190    { "0", "0x0", ios::hex | ios::showbase },
191    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
192
193    { "5/8", "5/8", ios::dec },
194    { "5/8", "0X5/0X8", ios::hex | ios::showbase | ios::uppercase },
195
196    // zero denominator with showbase
197    { "0/0",   "       0/0", ios::oct | ios::showbase, 10 },
198    { "0/0",   "       0/0", ios::dec | ios::showbase, 10 },
199    { "0/0",   "   0x0/0x0", ios::hex | ios::showbase, 10 },
200    { "123/0", "    0173/0", ios::oct | ios::showbase, 10 },
201    { "123/0", "     123/0", ios::dec | ios::showbase, 10 },
202    { "123/0", "  0x7b/0x0", ios::hex | ios::showbase, 10 },
203    { "123/0", "  0X7B/0X0", ios::hex | ios::showbase | ios::uppercase, 10 },
204    { "0/123", "    0/0173", ios::oct | ios::showbase, 10 },
205    { "0/123", "     0/123", ios::dec | ios::showbase, 10 },
206    { "0/123", "  0x0/0x7b", ios::hex | ios::showbase, 10 },
207    { "0/123", "  0X0/0X7B", ios::hex | ios::showbase | ios::uppercase, 10 },
208  };
209
210  size_t  i;
211  mpq_t   q;
212
213  mpq_init (q);
214
215#define mpq_integer_p(q)  (mpz_cmp_ui (mpq_denref(q), 1L) == 0)
216
217  for (i = 0; i < numberof (data); i++)
218    {
219      mpq_set_str_or_abort (q, data[i].q, 0);
220      MPZ_CHECK_FORMAT (mpq_numref (q));
221      MPZ_CHECK_FORMAT (mpq_denref (q));
222
223      if (option_check_standard
224	  && mpz_fits_slong_p (mpq_numref(q))
225	  && mpq_integer_p (q))
226	{
227	  ostringstream  got;
228	  long  n = mpz_get_si (mpq_numref(q));
229	  CALL (got << n);
230	  if (got.str().compare (data[i].want) != 0)
231	    {
232	      cout << "check_mpq data[" << i
233		   << "] doesn't match standard ostream output\n";
234	      cout << "  q:     " << data[i].q << "\n";
235	      cout << "  n:     " << n << "\n";
236	      DUMP ();
237	    }
238	}
239
240      {
241	ostringstream  got;
242	CALL (got << q);
243	if (got.str().compare (data[i].want) != 0)
244	  {
245	    cout << "mpq operator<< wrong, data[" << i << "]\n";
246	    cout << "  q:     " << data[i].q << "\n";
247	    ABORT ();
248	  }
249      }
250    }
251
252  mpq_clear (q);
253}
254
255
256void
257check_mpf (void)
258{
259  static const struct {
260    const char     *f;
261    const char     *want;
262    ios::fmtflags  flags;
263    int            width;
264    int            precision;
265    char           fill;
266
267  } data[] = {
268
269    { "0", "0",            ios::dec },
270    { "0", "+0",           ios::dec | ios::showpos },
271    { "0", "0.00000",      ios::dec | ios::showpoint },
272    { "0", "0",            ios::dec | ios::fixed },
273    { "0", "0.",           ios::dec | ios::fixed | ios::showpoint },
274    { "0", "0.000000e+00", ios::dec | ios::scientific },
275    { "0", "0.000000e+00", ios::dec | ios::scientific | ios::showpoint },
276
277    { "0", "0",          ios::dec, 0, 4 },
278    { "0", "0.000",      ios::dec | ios::showpoint, 0, 4 },
279    { "0", "0.0000",     ios::dec | ios::fixed, 0, 4 },
280    { "0", "0.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
281    { "0", "0.0000e+00", ios::dec | ios::scientific, 0, 4 },
282    { "0", "0.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
283
284    { "1", "1",       ios::dec },
285    { "1", "+1",      ios::dec | ios::showpos },
286    { "1", "1.00000", ios::dec | ios::showpoint },
287    { "1", "1",       ios::dec | ios::fixed },
288    { "1", "1.",      ios::dec | ios::fixed | ios::showpoint },
289    { "1", "1.000000e+00",   ios::dec | ios::scientific },
290    { "1", "1.000000e+00",  ios::dec | ios::scientific | ios::showpoint },
291
292    { "1", "1",          ios::dec,                   0, 4 },
293    { "1", "1.000",      ios::dec | ios::showpoint,  0, 4 },
294    { "1", "1.0000",     ios::dec | ios::fixed,      0, 4 },
295    { "1", "1.0000",     ios::dec | ios::fixed | ios::showpoint, 0, 4 },
296    { "1", "1.0000e+00", ios::dec | ios::scientific, 0, 4 },
297    { "1", "1.0000e+00", ios::dec | ios::scientific | ios::showpoint, 0, 4 },
298
299    { "-1", "-1",        ios::dec | ios::showpos },
300
301    { "-1", "  -1",      ios::dec, 4 },
302    { "-1", "-  1",      ios::dec | ios::internal, 4 },
303    { "-1", "-1  ",      ios::dec | ios::left, 4 },
304
305    { "-1", "  -0x1",    ios::hex | ios::showbase, 6 },
306    { "-1", "-0x  1",    ios::hex | ios::showbase | ios::internal, 6 },
307    { "-1", "-0x1  ",    ios::hex | ios::showbase | ios::left, 6 },
308
309    {    "1", "*********1", ios::dec, 10, 4, '*' },
310    { "1234", "******1234", ios::dec, 10, 4, '*' },
311    { "1234", "*****1234.", ios::dec | ios::showpoint, 10, 4, '*' },
312
313    { "12345", "1.23e+04", ios::dec, 0, 3 },
314
315    { "12345", "12345.", ios::dec | ios::fixed | ios::showpoint },
316
317    { "1.9999999",    "2",     ios::dec, 0, 1 },
318    { "1.0009999999", "1.001", ios::dec, 0, 4 },
319    { "1.0001",       "1",     ios::dec, 0, 4 },
320    { "1.0004",       "1",     ios::dec, 0, 4 },
321    { "1.000555",     "1.001", ios::dec, 0, 4 },
322
323    { "1.0002",       "1.000", ios::dec | ios::fixed, 0, 3 },
324    { "1.0008",       "1.001", ios::dec | ios::fixed, 0, 3 },
325
326    { "0", "0", ios::hex },
327    { "0", "0x0", ios::hex | ios::showbase },
328    { "0", "0X0", ios::hex | ios::showbase | ios::uppercase },
329    { "123",   "7b", ios::hex },
330    { "123", "0x7b", ios::hex | ios::showbase },
331    { "123", "0X7B", ios::hex | ios::showbase | ios::uppercase },
332
333    { "0", "0.000@+00", ios::hex | ios::scientific, 0, 3 },
334    { "256", "1.000@+02", ios::hex | ios::scientific, 0, 3 },
335
336    { "123",   "7.b@+01", ios::hex | ios::scientific, 0, 1 },
337    { "123",   "7.B@+01", ios::hex | ios::scientific | ios::uppercase, 0, 1 },
338    { "123", "0x7.b@+01", ios::hex | ios::scientific | ios::showbase, 0, 1 },
339    { "123", "0X7.B@+01",
340      ios::hex | ios::scientific | ios::showbase | ios::uppercase, 0, 1 },
341
342    { "1099511627776", "1.0@+10", ios::hex | ios::scientific, 0, 1 },
343    { "1099511627776", "1.0@+10",
344      ios::hex | ios::scientific | ios::uppercase, 0, 1 },
345
346    { "0.0625", "1.00@-01", ios::hex | ios::scientific, 0, 2 },
347
348    { "0", "0", ios::oct },
349    { "123",  "173", ios::oct },
350    { "123", "0173", ios::oct | ios::showbase },
351
352    // octal showbase suppressed for 0
353    { "0", "0", ios::oct | ios::showbase },
354    { ".125",    "00.1",  ios::oct | ios::showbase, 0, 1 },
355    { ".015625", "00.01", ios::oct | ios::showbase, 0, 2 },
356    { ".125",    "00.1",  ios::fixed | ios::oct | ios::showbase, 0, 1 },
357    { ".015625", "0.0",   ios::fixed | ios::oct | ios::showbase, 0, 1 },
358    { ".015625", "00.01", ios::fixed | ios::oct | ios::showbase, 0, 2 },
359
360    {  "0.125",  "1.000000e-01", ios::oct | ios::scientific },
361    {  "0.125", "+1.000000e-01", ios::oct | ios::scientific | ios::showpos },
362    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific },
363    { "-0.125", "-1.000000e-01", ios::oct | ios::scientific | ios::showpos },
364
365    { "0", "0.000e+00", ios::oct | ios::scientific, 0, 3 },
366    { "256",  "4.000e+02", ios::oct | ios::scientific, 0, 3 },
367    { "256", "04.000e+02", ios::oct | ios::scientific | ios::showbase, 0, 3 },
368    { "256",  "4.000E+02", ios::oct | ios::scientific | ios::uppercase, 0, 3 },
369    { "256", "04.000E+02",
370      ios::oct | ios::scientific | ios::showbase | ios::uppercase, 0, 3 },
371
372    { "16777216",    "1.000000e+08", ios::oct | ios::scientific },
373    { "16777216",    "1.000000E+08",
374      ios::oct | ios::scientific | ios::uppercase },
375    { "16777216",   "01.000000e+08",
376      ios::oct | ios::scientific | ios::showbase },
377    { "16777216",   "01.000000E+08",
378      ios::oct | ios::scientific | ios::showbase | ios::uppercase },
379    { "16777216",  "+01.000000e+08",
380      ios::oct | ios::scientific | ios::showbase | ios::showpos },
381    { "16777216",  "+01.000000E+08", ios::oct | ios::scientific
382      | ios::showbase | ios::showpos | ios::uppercase },
383    { "-16777216", "-01.000000e+08",
384      ios::oct | ios::scientific | ios::showbase | ios::showpos },
385    { "-16777216", "-01.000000E+08", ios::oct | ios::scientific
386      | ios::showbase | ios::showpos | ios::uppercase },
387
388  };
389
390  size_t  i;
391  mpf_t   f, f2;
392  double  d;
393
394  mpf_init (f);
395  mpf_init (f2);
396
397  for (i = 0; i < numberof (data); i++)
398    {
399      mpf_set_str_or_abort (f, data[i].f, 0);
400
401      d = mpf_get_d (f);
402      mpf_set_d (f2, d);
403      if (option_check_standard && mpf_cmp (f, f2) == 0
404	  && ! (data[i].flags & (ios::hex | ios::oct | ios::showbase)))
405	{
406	  ostringstream  got;
407	  CALL (got << d);
408	  if (got.str().compare (data[i].want) != 0)
409	    {
410	      cout << "check_mpf data[" << i
411		   << "] doesn't match standard ostream output\n";
412	      cout << "  f:     " << data[i].f << "\n";
413	      cout << "  d:     " << d << "\n";
414	      DUMP ();
415	    }
416	}
417
418      {
419	ostringstream  got;
420	CALL (got << f);
421	if (got.str().compare (data[i].want) != 0)
422	  {
423	    cout << "mpf operator<< wrong, data[" << i << "]\n";
424	    cout << "  f:     " << data[i].f << "\n";
425	    ABORT ();
426	  }
427      }
428    }
429
430  mpf_clear (f);
431  mpf_clear (f2);
432}
433
434
435
436int
437main (int argc, char *argv[])
438{
439  if (argc > 1 && strcmp (argv[1], "-s") == 0)
440    option_check_standard = 1;
441
442  tests_start ();
443
444  check_mpz ();
445  check_mpq ();
446  check_mpf ();
447
448  tests_end ();
449  return 0;
450}
451