PPL  1.2
checked.cc
Go to the documentation of this file.
1 /* Helper functions for checked numbers.
2  Copyright (C) 2001-2010 Roberto Bagnara <bagnara@cs.unipr.it>
3  Copyright (C) 2010-2016 BUGSENG srl (http://bugseng.com)
4 
5 This file is part of the Parma Polyhedra Library (PPL).
6 
7 The PPL is free software; you can redistribute it and/or modify it
8 under the terms of the GNU General Public License as published by the
9 Free Software Foundation; either version 3 of the License, or (at your
10 option) any later version.
11 
12 The PPL is distributed in the hope that it will be useful, but WITHOUT
13 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
15 for more details.
16 
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software Foundation,
19 Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02111-1307, USA.
20 
21 For the most up-to-date information see the Parma Polyhedra Library
22 site: http://bugseng.com/products/ppl/ . */
23 
24 #include "ppl-config.h"
25 #include "checked_defs.hh"
26 #include "C_Integer.hh"
27 
28 namespace Parma_Polyhedra_Library {
29 
33 
34 namespace Checked {
35 
38 
39 struct number_struct {
40  unsigned int base;
43  std::string mantissa;
44  unsigned int base_for_exponent;
45  unsigned long exponent;
46 };
47 
53 inline int
54 get_digit(char c, unsigned int base = 10) {
55  unsigned int n;
56  switch (c) {
57  case '0': n = 0; break;
58  case '1': n = 1; break;
59  case '2': n = 2; break;
60  case '3': n = 3; break;
61  case '4': n = 4; break;
62  case '5': n = 5; break;
63  case '6': n = 6; break;
64  case '7': n = 7; break;
65  case '8': n = 8; break;
66  case '9': n = 9; break;
67  case 'a': case 'A': n = 10; break;
68  case 'b': case 'B': n = 11; break;
69  case 'c': case 'C': n = 12; break;
70  case 'd': case 'D': n = 13; break;
71  case 'e': case 'E': n = 14; break;
72  case 'f': case 'F': n = 15; break;
73  case 'g': case 'G': n = 16; break;
74  case 'h': case 'H': n = 17; break;
75  case 'i': case 'I': n = 18; break;
76  case 'j': case 'J': n = 19; break;
77  case 'k': case 'K': n = 20; break;
78  case 'l': case 'L': n = 21; break;
79  case 'm': case 'M': n = 22; break;
80  case 'n': case 'N': n = 23; break;
81  case 'o': case 'O': n = 24; break;
82  case 'p': case 'P': n = 25; break;
83  case 'q': case 'Q': n = 26; break;
84  case 'r': case 'R': n = 27; break;
85  case 's': case 'S': n = 28; break;
86  case 't': case 'T': n = 29; break;
87  case 'u': case 'U': n = 30; break;
88  case 'v': case 'V': n = 31; break;
89  case 'w': case 'W': n = 32; break;
90  case 'x': case 'X': n = 33; break;
91  case 'y': case 'Y': n = 34; break;
92  case 'z': case 'Z': n = 35; break;
93  default:
94  return -1;
95  }
96  if (n >= base) {
97  return -1;
98  }
99  return static_cast<int>(n);
100 }
101 
109 inline bool
110 sum_sign(bool& a_neg, unsigned long& a_mod,
111  bool b_neg, unsigned long b_mod) {
112  if (a_neg == b_neg) {
113  if (a_mod > C_Integer<unsigned long>::max - b_mod) {
114  return false;
115  }
116  a_mod += b_mod;
117  }
118  else if (a_mod >= b_mod) {
119  a_mod -= b_mod;
120  }
121  else {
122  a_neg = !a_neg;
123  a_mod = b_mod - a_mod;
124  }
125  return true;
126 }
127 
128 
134 Result
135 parse_number_part(std::istream& is, number_struct& numer) {
136  enum anonymous_enum { BASE, INTEGER, FRACTIONAL, EXPONENT } state = BASE;
137  PPL_UNINITIALIZED(unsigned long, max_exp_div);
138  PPL_UNINITIALIZED(int, max_exp_rem);
139  bool empty_exponent = true;
140  bool empty_mantissa = true;
141  long exponent_offset = 0;
142  unsigned exponent_offset_scale = 1;
143  numer.base = 10;
144  numer.base_for_exponent = 10;
145  numer.neg_mantissa = false;
146  numer.neg_exponent = false;
147  numer.mantissa.erase();
148  numer.exponent = 0;
149  char c;
150  do {
151  if (!is.get(c)) {
152  return V_CVT_STR_UNK;
153  }
154  } while (is_space(c));
155  switch (c) {
156  case '-':
157  numer.neg_mantissa = true;
158  // Fall through.
159  case '+':
160  if (!is.get(c)) {
161  return V_CVT_STR_UNK;
162  }
163  if (c == 'i' || c == 'I') {
164  goto infinity;
165  }
166  if (c != '.') {
167  break;
168  }
169  // Fall through.
170  case '.':
171  state = FRACTIONAL;
172  if (!is.get(c)) {
173  return V_CVT_STR_UNK;
174  }
175  break;
176  case 'n':
177  case 'N':
178  if (!is.get(c)) {
179  return V_CVT_STR_UNK;
180  }
181  if (c != 'a' && c != 'A') {
182  goto unexpected_char;
183  }
184  if (!is.get(c)) {
185  return V_CVT_STR_UNK;
186  }
187  if (c != 'n' && c != 'N') {
188  goto unexpected_char;
189  }
190  return V_NAN;
191  infinity:
192  case 'i':
193  case 'I':
194  if (!is.get(c)) {
195  return V_CVT_STR_UNK;
196  }
197  if (c != 'n' && c != 'n') {
198  goto unexpected_char;
199  }
200  if (!is.get(c)) {
201  return V_CVT_STR_UNK;
202  }
203  if (c != 'f' && c != 'F') {
204  goto unexpected_char;
205  }
207  }
208  if (state != FRACTIONAL) {
209  if (get_digit(c, 10) < 0) {
210  goto unexpected_char;
211  }
212  char d;
213  if (c == '0' && !is.get(d).fail()) {
214  if (d == 'x' || d == 'X') {
215  numer.base = 16;
216  numer.base_for_exponent = 16;
217  state = INTEGER;
218  if (!is.get(c)) {
219  return V_CVT_STR_UNK;
220  }
221  }
222  else {
223  is.unget();
224  }
225  }
226  }
227  do {
228  switch (state) {
229  case BASE:
230  if (get_digit(c, 10) >= 0) {
231  if (c != '0' || !numer.mantissa.empty()) {
232  numer.mantissa += c;
233  }
234  empty_mantissa = false;
235  break;
236  }
237  if (c == '^') {
238  if (!is.get(c)) {
239  return V_CVT_STR_UNK;
240  }
241  if (c != '^') {
242  goto unexpected_char;
243  }
244  numer.base = 0;
245  for (std::string::const_iterator
246  i = numer.mantissa.begin(); i != numer.mantissa.end(); ++i) {
247  numer.base = numer.base * 10 + static_cast<unsigned>(get_digit(*i, 10));
248  if (numer.base > 36) {
249  goto unexpected_char;
250  }
251  }
252  if (numer.base < 2) {
253  goto unexpected_char;
254  }
255  numer.base_for_exponent = numer.base;
256  numer.mantissa.erase();
257  empty_mantissa = true;
258  state = INTEGER;
259  break;
260  }
261  goto integer;
262  case INTEGER:
263  if (get_digit(c, numer.base) >= 0) {
264  if (c != '0' || !numer.mantissa.empty()) {
265  numer.mantissa += c;
266  }
267  empty_mantissa = false;
268  break;
269  }
270  integer:
271  if (c == '.') {
272  state = FRACTIONAL;
273  break;
274  }
275  goto fractional;
276  case FRACTIONAL:
277  if (get_digit(c, numer.base) >= 0) {
278  --exponent_offset;
279  if (c != '0' || !numer.mantissa.empty()) {
280  numer.mantissa += c;
281  }
282  empty_mantissa = false;
283  break;
284  }
285  fractional:
286  if (empty_mantissa) {
287  goto unexpected_char;
288  }
289  if (c == 'e' || c == 'E') {
290  goto exponent;
291  }
292  if (c == 'p' || c == 'P') {
293  if (numer.base == 16) {
294  numer.base_for_exponent = 2;
295  exponent_offset_scale = 4;
296  goto exponent;
297  }
298  else {
299  goto unexpected_char;
300  }
301  }
302  if (c == '*') {
303  if (!is.get(c)) {
304  return V_CVT_STR_UNK;
305  }
306  if (c != '^') {
307  goto unexpected_char;
308  }
309  exponent:
310  state = EXPONENT;
311  PPL_ASSERT(numer.base >= 2);
312  const long l_max = C_Integer<long>::max;
313  max_exp_div = static_cast<unsigned long>(l_max) / numer.base;
314  max_exp_rem = static_cast<int>(l_max % static_cast<long>(numer.base));
315  if (!is.get(c)) {
316  return V_CVT_STR_UNK;
317  }
318  if (c == '-') {
319  numer.neg_exponent = true;
320  break;
321  }
322  if (c == '+') {
323  break;
324  }
325  continue;
326  }
327  is.unget();
328  goto ok;
329  case EXPONENT:
330  const int d = get_digit(c, 10);
331  if (d >= 0) {
332  empty_exponent = false;
333  if (numer.exponent > max_exp_div
334  || (numer.exponent == max_exp_div && d > max_exp_rem)) {
335  return V_CVT_STR_UNK;
336  }
337  numer.exponent = 10 * numer.exponent + static_cast<unsigned long>(d);
338  break;
339  }
340  if (empty_exponent) {
341  goto unexpected_char;
342  }
343  is.unget();
344  goto ok;
345  }
346  is.get(c);
347  } while (!is.fail());
348 
349  if (empty_mantissa || is.bad()) {
350  return V_CVT_STR_UNK;
351  }
352 
353  ok:
354  {
355  std::string::size_type n = numer.mantissa.size();
356  while (n > 0 && numer.mantissa[n - 1] == '0') {
357  --n;
358  ++exponent_offset;
359  }
360  numer.mantissa.erase(n);
361  bool neg;
362  if (exponent_offset < 0) {
363  neg = true;
364  exponent_offset = -exponent_offset;
365  }
366  else {
367  neg = false;
368  }
369  sum_sign(numer.neg_exponent, numer.exponent,
370  neg, static_cast<unsigned long>(exponent_offset) * exponent_offset_scale);
371  return V_EQ;
372  }
373 
374  unexpected_char:
375  is.unget();
376  return V_CVT_STR_UNK;
377 }
378 
384 Result
385 parse_number(std::istream& is, number_struct& numer, number_struct& denom) {
386  // Read the numerator.
387  Result r = parse_number_part(is, numer);
388  if (r != V_EQ) {
389  return r;
390  }
391  char c;
392  is.get(c);
393  if (is.bad()) {
394  return V_CVT_STR_UNK;
395  }
396  if (!is) {
397  denom.base = 0;
398  return r;
399  }
400  if (c != '/') {
401  is.unget();
402  denom.base = 0;
403  return r;
404  }
405  // Read the denominator.
406  r = parse_number_part(is, denom);
407  if (r != V_EQ) {
408  return V_CVT_STR_UNK;
409  }
410  if (numer.base == denom.base
411  && numer.base_for_exponent == denom.base_for_exponent) {
412  if (sum_sign(numer.neg_exponent, numer.exponent,
413  !denom.neg_exponent, denom.exponent)) {
414  if (numer.neg_exponent) {
415  denom.neg_exponent = false;
416  denom.exponent = numer.exponent;
417  numer.exponent = 0;
418  }
419  else {
420  denom.exponent = 0;
421  }
422  }
423  }
424  return V_EQ;
425 }
426 
427 
428 Result
429 input_mpq(mpq_class& to, std::istream& is) {
430  number_struct numer_struct;
431  number_struct denom_struct;
432  const Result r = parse_number(is, numer_struct, denom_struct);
433  if (r == V_CVT_STR_UNK) {
434  is.setstate(is.failbit);
435  return r;
436  }
437  is.clear(is.rdstate() & ~is.failbit);
438  if (r != V_EQ) {
439  return r;
440  }
441  if (denom_struct.base != 0 && denom_struct.mantissa.empty()) {
442  return V_NAN;
443  }
444  if (numer_struct.mantissa.empty()) {
445  to = 0;
446  return V_EQ;
447  }
448  const mpz_ptr numer = to.get_num().get_mpz_t();
449  const mpz_ptr denom = to.get_den().get_mpz_t();
450  mpz_set_str(numer, numer_struct.mantissa.c_str(),
451  static_cast<int>(numer_struct.base));
452  if (denom_struct.base != 0) {
453  if (numer_struct.neg_mantissa != denom_struct.neg_mantissa) {
454  mpz_neg(numer, numer);
455  }
456  mpz_set_str(denom, denom_struct.mantissa.c_str(),
457  static_cast<int>(denom_struct.base));
458  if (numer_struct.exponent != 0 || denom_struct.exponent != 0) {
459  // Multiply the exponents into the numerator and denominator.
460  mpz_t z;
461  mpz_init(z);
462  if (numer_struct.exponent != 0) {
463  mpz_ui_pow_ui(z,
464  numer_struct.base_for_exponent, numer_struct.exponent);
465  if (numer_struct.neg_exponent) {
466  mpz_mul(denom, denom, z);
467  }
468  else {
469  mpz_mul(numer, numer, z);
470  }
471  }
472  if (denom_struct.exponent != 0) {
473  mpz_ui_pow_ui(z,
474  denom_struct.base_for_exponent, denom_struct.exponent);
475  if (denom_struct.neg_exponent) {
476  mpz_mul(numer, numer, z);
477  }
478  else {
479  mpz_mul(denom, denom, z);
480  }
481  }
482  mpz_clear(z);
483  }
484  }
485  else {
486  if (numer_struct.neg_mantissa) {
487  mpz_neg(numer, numer);
488  }
489  if (numer_struct.exponent != 0) {
490  if (numer_struct.neg_exponent) {
491  // Add the negative exponent as a denominator.
492  mpz_ui_pow_ui(denom,
493  numer_struct.base_for_exponent, numer_struct.exponent);
494  goto end;
495  }
496  // Multiply the exponent into the numerator.
497  mpz_t z;
498  mpz_init(z);
499  mpz_ui_pow_ui(z,
500  numer_struct.base_for_exponent, numer_struct.exponent);
501  mpz_mul(numer, numer, z);
502  mpz_clear(z);
503  }
504  mpz_set_ui(denom, 1);
505  return V_EQ;
506  }
507  end:
508  // GMP operators require rationals in canonical form.
509  to.canonicalize();
510  return V_EQ;
511 }
512 
513 /* NOTE: q is overwritten! */
514 std::string float_mpq_to_string(mpq_class& q) {
515  const mpz_ptr n = q.get_num().get_mpz_t();
516  const mpz_ptr d = q.get_den().get_mpz_t();
517  const unsigned long decimals = mpz_sizeinbase(d, 2) - 1;
518  if (decimals != 0) {
519  mpz_ui_pow_ui(d, 5, decimals);
520  mpz_mul(n, n, d);
521  }
522  size_t bufsize = mpz_sizeinbase(n, 10);
523  if (bufsize < decimals) {
524  bufsize = decimals + 4;
525  }
526  else {
527  bufsize += 3;
528  }
529  char buf[bufsize];
530  mpz_get_str(buf, 10, n);
531  if (decimals != 0) {
532  const size_t len = strlen(buf);
533  if (decimals < len) {
534  memmove(&buf[len - decimals + 1], &buf[len - decimals], decimals + 1);
535  buf[len - decimals] = '.';
536  }
537  else {
538  const size_t zeroes = decimals - len;
539  memmove(&buf[2 + zeroes], &buf[0], len + 1);
540  buf[0] = '0';
541  buf[1] = '.';
542  memset(&buf[2], '0', zeroes);
543  }
544  }
545  return buf;
546 }
547 
548 } // namespace Checked
549 
550 } // namespace Parma_Polyhedra_Library
int get_digit(char c, unsigned int base=10)
Returns the integer value associated with the ASCII code c, in the base base positional number system...
Definition: checked.cc:54
The computed result is exact.
Definition: Result_defs.hh:81
std::string float_mpq_to_string(mpq_class &q)
Definition: checked.cc:514
Not_A_Number NOT_A_NUMBER
Definition: checked.cc:32
unsigned irrational_precision
Holds the precision parameter used for irrational calculations.
Definition: checked.cc:37
Result
Possible outcomes of a checked arithmetic computation.
Definition: Result_defs.hh:76
bool is_space(char c)
Returns true if c is any kind of space character.
Not a number result.
Definition: Result_defs.hh:123
Converting from unknown string.
Definition: Result_defs.hh:126
Result parse_number(std::istream &is, number_struct &numer, number_struct &denom)
Reads a number from is writing it into numer, the numerator, and denom, the denominator; the appropri...
Definition: checked.cc:385
Plus_Infinity PLUS_INFINITY
Definition: checked.cc:31
The entire library is confined to this namespace.
Definition: version.hh:61
Minus_Infinity MINUS_INFINITY
Definition: checked.cc:30
Result input_mpq(mpq_class &to, std::istream &is)
Definition: checked.cc:429
bool sum_sign(bool &a_neg, unsigned long &a_mod, bool b_neg, unsigned long b_mod)
Adds the number represented (in the modulus-and-sign representation) by b_neg and b_mod to the number...
Definition: checked.cc:110
Result parse_number_part(std::istream &is, number_struct &numer)
Helper function for parse_number(): reads the numerator or denominator part of a number from is into ...
Definition: checked.cc:135
Coefficient c
Definition: PIP_Tree.cc:64
#define PPL_UNINITIALIZED(type, name)
Definition: compiler.hh:72