1/* Test istream formatted input. 2 3Copyright 2001, 2002, 2003, 2004 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#include <cstring> 23 24#include "gmp.h" 25#include "gmp-impl.h" 26#include "tests.h" 27 28using namespace std; 29 30 31// Under option_check_standard, the various test cases for mpz operator>> 32// are put through the standard operator>> for long, and likewise mpf 33// operator>> is put through double. 34// 35// In g++ 3.3 this results in some printouts about the final position 36// indicated for something like ".e123". Our mpf code stops at the "e" 37// since there's no mantissa digits, but g++ reads the whole thing and only 38// then decides it's bad. 39 40int option_check_standard = 0; 41 42 43// On some versions of g++ 2.96 it's been observed that putback() may leave 44// tellg() unchanged. We believe this is incorrect and presumably the 45// result of a bug, since for instance it's ok in g++ 2.95 and g++ 3.3. We 46// detect the problem at runtime and disable affected checks. 47 48int putback_tellg_works = 1; 49 50void 51check_putback_tellg (void) 52{ 53 istringstream input ("hello"); 54 streampos old_pos, new_pos; 55 char c; 56 57 input.get(c); 58 old_pos = input.tellg(); 59 input.putback(c); 60 new_pos = input.tellg(); 61 62 if (old_pos == new_pos) 63 { 64 cout << "Warning, istringstream has a bug: putback() doesn't update tellg().\n";; 65 cout << "Tests on tellg() will be skipped.\n"; 66 putback_tellg_works = 0; 67 } 68} 69 70 71#define WRONG(str) \ 72 do { \ 73 cout << str ", data[" << i << "]\n"; \ 74 cout << " input: \"" << data[i].input << "\"\n"; \ 75 cout << " flags: " << hex << input.flags() << dec << "\n"; \ 76 } while (0) 77 78void 79check_mpz (void) 80{ 81 static const struct { 82 const char *input; 83 int want_pos; 84 const char *want; 85 ios::fmtflags flags; 86 87 } data[] = { 88 89 { "0", -1, "0", (ios::fmtflags) 0 }, 90 { "123", -1, "123", (ios::fmtflags) 0 }, 91 { "0123", -1, "83", (ios::fmtflags) 0 }, 92 { "0x123", -1, "291", (ios::fmtflags) 0 }, 93 { "-123", -1, "-123", (ios::fmtflags) 0 }, 94 { "-0123", -1, "-83", (ios::fmtflags) 0 }, 95 { "-0x123", -1, "-291", (ios::fmtflags) 0 }, 96 { "+123", -1, "123", (ios::fmtflags) 0 }, 97 { "+0123", -1, "83", (ios::fmtflags) 0 }, 98 { "+0x123", -1, "291", (ios::fmtflags) 0 }, 99 100 { "0", -1, "0", ios::dec }, 101 { "1f", 1, "1", ios::dec }, 102 { "011f", 3, "11", ios::dec }, 103 { "123", -1, "123", ios::dec }, 104 { "-1f", 2, "-1", ios::dec }, 105 { "-011f", 4, "-11", ios::dec }, 106 { "-123", -1, "-123", ios::dec }, 107 { "+1f", 2, "1", ios::dec }, 108 { "+011f", 4, "11", ios::dec }, 109 { "+123", -1, "123", ios::dec }, 110 111 { "0", -1, "0", ios::oct }, 112 { "123", -1, "83", ios::oct }, 113 { "-123", -1, "-83", ios::oct }, 114 { "+123", -1, "83", ios::oct }, 115 116 { "0", -1, "0", ios::hex }, 117 { "123", -1, "291", ios::hex }, 118 { "ff", -1, "255", ios::hex }, 119 { "FF", -1, "255", ios::hex }, 120 { "-123", -1, "-291", ios::hex }, 121 { "-ff", -1, "-255", ios::hex }, 122 { "-FF", -1, "-255", ios::hex }, 123 { "+123", -1, "291", ios::hex }, 124 { "+ff", -1, "255", ios::hex }, 125 { "+FF", -1, "255", ios::hex }, 126 { "ab", -1, "171", ios::hex }, 127 { "cd", -1, "205", ios::hex }, 128 { "ef", -1, "239", ios::hex }, 129 130 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 131 { " 123", -1, "123", ios::skipws }, 132 }; 133 134 mpz_t got, want; 135 int got_ok, want_ok; 136 long got_si, want_si; 137 streampos init_tellg, got_pos, want_pos; 138 139 mpz_init (got); 140 mpz_init (want); 141 142 for (size_t i = 0; i < numberof (data); i++) 143 { 144 want_pos = (data[i].want_pos == -1 145 ? strlen (data[i].input) : data[i].want_pos); 146 147 want_ok = (data[i].want != NULL); 148 149 if (data[i].want != NULL) 150 mpz_set_str_or_abort (want, data[i].want, 0); 151 else 152 mpz_set_ui (want, 0L); 153 154 if (option_check_standard && mpz_fits_slong_p (want)) 155 { 156 istringstream input (data[i].input); 157 input.flags (data[i].flags); 158 init_tellg = input.tellg(); 159 want_si = mpz_get_si (want); 160 161 input >> got_si; 162 got_ok = (input ? 1 : 0); 163 input.clear(); 164 got_pos = input.tellg() - init_tellg; 165 166 if (got_ok != want_ok) 167 { 168 WRONG ("stdc++ operator>> wrong status, check_mpz"); 169 cout << " want_ok: " << want_ok << "\n"; 170 cout << " got_ok: " << got_ok << "\n"; 171 } 172 if (want_ok && got_si != want_si) 173 { 174 WRONG ("stdc++ operator>> wrong result, check_mpz"); 175 cout << " got_si: " << got_si << "\n"; 176 cout << " want_si: " << want_si << "\n"; 177 } 178 if (putback_tellg_works && got_pos != want_pos) 179 { 180 WRONG ("stdc++ operator>> wrong position, check_mpz"); 181 cout << " want_pos: " << want_pos << "\n"; 182 cout << " got_pos: " << got_pos << "\n"; 183 } 184 } 185 186 { 187 istringstream input (data[i].input); 188 input.flags (data[i].flags); 189 init_tellg = input.tellg(); 190 191 mpz_set_ui (got, 0xDEAD); 192 input >> got; 193 got_ok = (input ? 1 : 0); 194 input.clear(); 195 got_pos = input.tellg() - init_tellg; 196 197 if (got_ok != want_ok) 198 { 199 WRONG ("mpz operator>> wrong status"); 200 cout << " want_ok: " << want_ok << "\n"; 201 cout << " got_ok: " << got_ok << "\n"; 202 abort (); 203 } 204 if (want_ok && mpz_cmp (got, want) != 0) 205 { 206 WRONG ("mpz operator>> wrong result"); 207 mpz_trace (" got ", got); 208 mpz_trace (" want", want); 209 abort (); 210 } 211 if (putback_tellg_works && got_pos != want_pos) 212 { 213 WRONG ("mpz operator>> wrong position"); 214 cout << " want_pos: " << want_pos << "\n"; 215 cout << " got_pos: " << got_pos << "\n"; 216 abort (); 217 } 218 } 219 } 220 221 mpz_clear (got); 222 mpz_clear (want); 223} 224 225void 226check_mpq (void) 227{ 228 static const struct { 229 const char *input; 230 int want_pos; 231 const char *want; 232 ios::fmtflags flags; 233 234 } data[] = { 235 236 { "0", -1, "0", (ios::fmtflags) 0 }, 237 { "00", -1, "0", (ios::fmtflags) 0 }, 238 { "0x0", -1, "0", (ios::fmtflags) 0 }, 239 240 { "123/456", -1, "123/456", ios::dec }, 241 { "0123/456", -1, "123/456", ios::dec }, 242 { "123/0456", -1, "123/456", ios::dec }, 243 { "0123/0456", -1, "123/456", ios::dec }, 244 245 { "123/456", -1, "83/302", ios::oct }, 246 { "0123/456", -1, "83/302", ios::oct }, 247 { "123/0456", -1, "83/302", ios::oct }, 248 { "0123/0456", -1, "83/302", ios::oct }, 249 250 { "ab", -1, "171", ios::hex }, 251 { "cd", -1, "205", ios::hex }, 252 { "ef", -1, "239", ios::hex }, 253 254 { "0/0", -1, "0/0", (ios::fmtflags) 0 }, 255 { "5/8", -1, "5/8", (ios::fmtflags) 0 }, 256 { "0x5/0x8", -1, "5/8", (ios::fmtflags) 0 }, 257 258 { "123/456", -1, "123/456", (ios::fmtflags) 0 }, 259 { "123/0456", -1, "123/302", (ios::fmtflags) 0 }, 260 { "123/0x456", -1, "123/1110", (ios::fmtflags) 0 }, 261 { "123/0X456", -1, "123/1110", (ios::fmtflags) 0 }, 262 263 { "0123/123", -1, "83/123", (ios::fmtflags) 0 }, 264 { "0123/0123", -1, "83/83", (ios::fmtflags) 0 }, 265 { "0123/0x123", -1, "83/291", (ios::fmtflags) 0 }, 266 { "0123/0X123", -1, "83/291", (ios::fmtflags) 0 }, 267 268 { "0x123/123", -1, "291/123", (ios::fmtflags) 0 }, 269 { "0X123/0123", -1, "291/83", (ios::fmtflags) 0 }, 270 { "0x123/0x123", -1, "291/291", (ios::fmtflags) 0 }, 271 272 { " 123", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 273 { " 123", -1, "123", ios::skipws }, 274 }; 275 276 mpq_t got, want; 277 int got_ok, want_ok; 278 long got_si, want_si; 279 streampos init_tellg, got_pos, want_pos; 280 281 mpq_init (got); 282 mpq_init (want); 283 284 for (size_t i = 0; i < numberof (data); i++) 285 { 286 want_pos = (data[i].want_pos == -1 287 ? strlen (data[i].input) : data[i].want_pos); 288 289 want_ok = (data[i].want != NULL); 290 291 if (data[i].want != NULL) 292 mpq_set_str_or_abort (want, data[i].want, 0); 293 else 294 mpq_set_ui (want, 0L, 1L); 295 296 if (option_check_standard 297 && mpz_fits_slong_p (mpq_numref(want)) 298 && mpz_cmp_ui (mpq_denref(want), 1L) == 0) 299 { 300 istringstream input (data[i].input); 301 input.flags (data[i].flags); 302 init_tellg = input.tellg(); 303 want_si = mpz_get_si (mpq_numref(want)); 304 305 input >> got_si; 306 got_ok = (input ? 1 : 0); 307 input.clear(); 308 got_pos = input.tellg() - init_tellg; 309 310 if (got_ok != want_ok) 311 { 312 WRONG ("stdc++ operator>> wrong status, check_mpq"); 313 cout << " want_ok: " << want_ok << "\n"; 314 cout << " got_ok: " << got_ok << "\n"; 315 } 316 if (want_ok && want_si != got_si) 317 { 318 WRONG ("stdc++ operator>> wrong result, check_mpq"); 319 cout << " got_si: " << got_si << "\n"; 320 cout << " want_si: " << want_si << "\n"; 321 } 322 if (putback_tellg_works && got_pos != want_pos) 323 { 324 WRONG ("stdc++ operator>> wrong position, check_mpq"); 325 cout << " want_pos: " << want_pos << "\n"; 326 cout << " got_pos: " << got_pos << "\n"; 327 } 328 } 329 330 { 331 istringstream input (data[i].input); 332 input.flags (data[i].flags); 333 init_tellg = input.tellg(); 334 mpq_set_si (got, 0xDEAD, 0xBEEF); 335 336 input >> got; 337 got_ok = (input ? 1 : 0); 338 input.clear(); 339 got_pos = input.tellg() - init_tellg; 340 341 if (got_ok != want_ok) 342 { 343 WRONG ("mpq operator>> wrong status"); 344 cout << " want_ok: " << want_ok << "\n"; 345 cout << " got_ok: " << got_ok << "\n"; 346 abort (); 347 } 348 // don't use mpq_equal, since we allow non-normalized values to be 349 // read, which can trigger ASSERTs in mpq_equal 350 if (want_ok && (mpz_cmp (mpq_numref (got), mpq_numref(want)) != 0 351 || mpz_cmp (mpq_denref (got), mpq_denref(want)) != 0)) 352 { 353 WRONG ("mpq operator>> wrong result"); 354 mpq_trace (" got ", got); 355 mpq_trace (" want", want); 356 abort (); 357 } 358 if (putback_tellg_works && got_pos != want_pos) 359 { 360 WRONG ("mpq operator>> wrong position"); 361 cout << " want_pos: " << want_pos << "\n"; 362 cout << " got_pos: " << got_pos << "\n"; 363 abort (); 364 } 365 } 366 } 367 368 mpq_clear (got); 369 mpq_clear (want); 370} 371 372 373void 374check_mpf (void) 375{ 376 static const struct { 377 const char *input; 378 int want_pos; 379 const char *want; 380 ios::fmtflags flags; 381 382 } data[] = { 383 384 { "0", -1, "0", (ios::fmtflags) 0 }, 385 { "+0", -1, "0", (ios::fmtflags) 0 }, 386 { "-0", -1, "0", (ios::fmtflags) 0 }, 387 { "0.0", -1, "0", (ios::fmtflags) 0 }, 388 { "0.", -1, "0", (ios::fmtflags) 0 }, 389 { ".0", -1, "0", (ios::fmtflags) 0 }, 390 { "+.0", -1, "0", (ios::fmtflags) 0 }, 391 { "-.0", -1, "0", (ios::fmtflags) 0 }, 392 { "+0.00", -1, "0", (ios::fmtflags) 0 }, 393 { "-0.000", -1, "0", (ios::fmtflags) 0 }, 394 { "+0.00", -1, "0", (ios::fmtflags) 0 }, 395 { "-0.000", -1, "0", (ios::fmtflags) 0 }, 396 { "0.0e0", -1, "0", (ios::fmtflags) 0 }, 397 { "0.e0", -1, "0", (ios::fmtflags) 0 }, 398 { ".0e0", -1, "0", (ios::fmtflags) 0 }, 399 { "0.0e-0", -1, "0", (ios::fmtflags) 0 }, 400 { "0.e-0", -1, "0", (ios::fmtflags) 0 }, 401 { ".0e-0", -1, "0", (ios::fmtflags) 0 }, 402 { "0.0e+0", -1, "0", (ios::fmtflags) 0 }, 403 { "0.e+0", -1, "0", (ios::fmtflags) 0 }, 404 { ".0e+0", -1, "0", (ios::fmtflags) 0 }, 405 406 { "1", -1, "1", (ios::fmtflags) 0 }, 407 { "+1", -1, "1", (ios::fmtflags) 0 }, 408 { "-1", -1, "-1", (ios::fmtflags) 0 }, 409 410 { " 0", 0, NULL, (ios::fmtflags) 0 }, // not without skipws 411 { " 0", -1, "0", ios::skipws }, 412 { " +0", -1, "0", ios::skipws }, 413 { " -0", -1, "0", ios::skipws }, 414 415 { "+-123", 1, NULL, (ios::fmtflags) 0 }, 416 { "-+123", 1, NULL, (ios::fmtflags) 0 }, 417 { "1e+-123", 3, NULL, (ios::fmtflags) 0 }, 418 { "1e-+123", 3, NULL, (ios::fmtflags) 0 }, 419 420 { "e123", 0, NULL, (ios::fmtflags) 0 }, // at least one mantissa digit 421 { ".e123", 1, NULL, (ios::fmtflags) 0 }, 422 { "+.e123", 2, NULL, (ios::fmtflags) 0 }, 423 { "-.e123", 2, NULL, (ios::fmtflags) 0 }, 424 425 { "123e", 4, NULL, (ios::fmtflags) 0 }, // at least one exponent digit 426 { "123e-", 5, NULL, (ios::fmtflags) 0 }, 427 { "123e+", 5, NULL, (ios::fmtflags) 0 }, 428 }; 429 430 mpf_t got, want; 431 int got_ok, want_ok; 432 double got_d, want_d; 433 streampos init_tellg, got_pos, want_pos; 434 435 mpf_init (got); 436 mpf_init (want); 437 438 for (size_t i = 0; i < numberof (data); i++) 439 { 440 want_pos = (data[i].want_pos == -1 441 ? strlen (data[i].input) : data[i].want_pos); 442 443 want_ok = (data[i].want != NULL); 444 445 if (data[i].want != NULL) 446 mpf_set_str_or_abort (want, data[i].want, 0); 447 else 448 mpf_set_ui (want, 0L); 449 450 want_d = mpf_get_d (want); 451 if (option_check_standard && mpf_cmp_d (want, want_d) == 0) 452 { 453 istringstream input (data[i].input); 454 input.flags (data[i].flags); 455 init_tellg = input.tellg(); 456 457 input >> got_d; 458 got_ok = (input ? 1 : 0); 459 input.clear(); 460 got_pos = input.tellg() - init_tellg; 461 462 if (got_ok != want_ok) 463 { 464 WRONG ("stdc++ operator>> wrong status, check_mpf"); 465 cout << " want_ok: " << want_ok << "\n"; 466 cout << " got_ok: " << got_ok << "\n"; 467 } 468 if (want_ok && want_d != got_d) 469 { 470 WRONG ("stdc++ operator>> wrong result, check_mpf"); 471 cout << " got: " << got_d << "\n"; 472 cout << " want: " << want_d << "\n"; 473 } 474 if (putback_tellg_works && got_pos != want_pos) 475 { 476 WRONG ("stdc++ operator>> wrong position, check_mpf"); 477 cout << " want_pos: " << want_pos << "\n"; 478 cout << " got_pos: " << got_pos << "\n"; 479 } 480 } 481 482 { 483 istringstream input (data[i].input); 484 input.flags (data[i].flags); 485 init_tellg = input.tellg(); 486 487 mpf_set_ui (got, 0xDEAD); 488 input >> got; 489 got_ok = (input ? 1 : 0); 490 input.clear(); 491 got_pos = input.tellg() - init_tellg; 492 493 if (got_ok != want_ok) 494 { 495 WRONG ("mpf operator>> wrong status"); 496 cout << " want_ok: " << want_ok << "\n"; 497 cout << " got_ok: " << got_ok << "\n"; 498 abort (); 499 } 500 if (want_ok && mpf_cmp (got, want) != 0) 501 { 502 WRONG ("mpf operator>> wrong result"); 503 mpf_trace (" got ", got); 504 mpf_trace (" want", want); 505 abort (); 506 } 507 if (putback_tellg_works && got_pos != want_pos) 508 { 509 WRONG ("mpf operator>> wrong position"); 510 cout << " want_pos: " << want_pos << "\n"; 511 cout << " got_pos: " << got_pos << "\n"; 512 abort (); 513 } 514 } 515 } 516 517 mpf_clear (got); 518 mpf_clear (want); 519} 520 521 522 523int 524main (int argc, char *argv[]) 525{ 526 if (argc > 1 && strcmp (argv[1], "-s") == 0) 527 option_check_standard = 1; 528 529 tests_start (); 530 531 check_putback_tellg (); 532 check_mpz (); 533 check_mpq (); 534 check_mpf (); 535 536 tests_end (); 537 return 0; 538} 539