Boost.Real  1.0.0
Boost.Real numerical data type for real numbers representation using range arithmetic.
real_explicit.hpp
1 #ifndef BOOST_REAL_REAL_EXPLICIT_HPP
2 #define BOOST_REAL_REAL_EXPLICIT_HPP
3 
4 #include <vector>
5 #include <iostream>
6 #include <initializer_list>
7 #include <string>
8 
9 #include <real/real_exception.hpp>
10 #include <real/real_helpers.hpp>
11 #include <real/interval.hpp>
12 
13 namespace boost {
14  namespace real {
15 
22  class real_explicit {
23 
24  // Number representation as a vector of digits with an integer part and a sign (+/-)
25  // TODO: Replace this by a boost::real::boundary type
26  // TODO: Add normalizations to the constructors
27  std::vector<int> _digits = {};
28  int _exponent = 1;
29  bool _positive = true;
30 
31  // The number max precision is the same as the explicit number digits size
32  unsigned int _maximum_precision = 1;
33  public:
34 
43  private:
44 
45  // Iterator precision
46  int _n;
47 
48  // Internal number to iterate
49  real_explicit const* _real_ptr = nullptr;
50 
51  void check_and_swap_boundaries() {
52  if (!this->_real_ptr->_positive) {
53  this->approximation_interval.swap_bounds();
54  }
55  }
56 
57  public:
58 
59  // Number approximation_interval boundaries
60  boost::real::interval approximation_interval;
61 
66  const_precision_iterator() = default;
67 
75  const_precision_iterator(const const_precision_iterator& other) = default;
76 
85  explicit const_precision_iterator(real_explicit const* real_number) : _n(1), _real_ptr(real_number) {
86  this->approximation_interval.lower_bound.exponent = this->_real_ptr->_exponent;
87  this->approximation_interval.upper_bound.exponent = this->_real_ptr->_exponent;
88  this->approximation_interval.lower_bound.positive = this->_real_ptr->_positive;
89  this->approximation_interval.upper_bound.positive = this->_real_ptr->_positive;
90 
91  int first_digit = this->_real_ptr->_digits[0];
92  this->approximation_interval.lower_bound.digits.push_back(first_digit);
93 
94  if (first_digit == 10) {
95  this->approximation_interval.upper_bound.digits.push_back(1);
96  this->approximation_interval.upper_bound.exponent++;
97  } else if (this->_n < (int)this->_real_ptr->_digits.size()) {
98  this->approximation_interval.upper_bound.digits.push_back(first_digit + 1);
99  } else {
100  this->approximation_interval.upper_bound.digits.push_back(first_digit);
101  }
102 
103  this->check_and_swap_boundaries();
104  }
105 
110  void operator++() {
111  this->iterate_n_times(1);
112  }
113 
118  void iterate_n_times(int n) {
119  // If the explicit number full precision has been already reached (the end)
120  // is the end of the iterator
121  if (this->_n >= (int)this->_real_ptr->_digits.size()) {
122  // TODO: Remove commented lines that are deprecatod code
123  //this->approximation_interval.lower_bound.push_back(0);
124  //this->approximation_interval.upper_bound.push_back(0);
125  //this->_n++;
126  return;
127  }
128 
129  // If the number is negative, boundaries are interpreted as mirrored:
130  // First, the operation is made as positive, and after boundary calculation
131  // boundaries are swapped to come back to the negative representation.
132  this->check_and_swap_boundaries();
133 
134  // If the explicit number just reaches the full precision (the end)
135  // then set both boundaries are equals
136  if (this->_n + n >= (int)this->_real_ptr->_digits.size()) {
137 
138  for(int i = this->_n; i < (int)this->_real_ptr->_digits.size(); i++) {
139  this->approximation_interval.lower_bound.push_back(this->_real_ptr->_digits[i]);
140  }
141  this->approximation_interval.upper_bound = this->approximation_interval.lower_bound;
142 
143 
144  } else {
145 
146  // If the explicit number didn't reaches the full precision (the end)
147  // then the number interval is defined by truncation.
148 
149  for(int i = 0; i < n; i++) {
150  this->approximation_interval.lower_bound.push_back(this->_real_ptr->_digits[this->_n]);
151  }
152 
153  this->approximation_interval.upper_bound.clear();
154  this->approximation_interval.upper_bound.digits.resize(this->approximation_interval.lower_bound.size());
155 
156  int carry = 1;
157  for (int i = (int)this->approximation_interval.lower_bound.size() - 1; i >= 0; --i) {
158  if (this->approximation_interval.lower_bound[i] + carry == 10) {
159  this->approximation_interval.upper_bound[i] = 0;
160  } else {
161  this->approximation_interval.upper_bound[i] = this->approximation_interval.lower_bound[i] + carry;
162  carry = 0;
163  }
164  }
165 
166  if (carry > 0) {
167  this->approximation_interval.upper_bound.push_front(carry);
168  this->approximation_interval.upper_bound.exponent = this->approximation_interval.lower_bound.exponent + 1;
169  } else {
170  this->approximation_interval.upper_bound.exponent = this->approximation_interval.lower_bound.exponent;
171  }
172  }
173 
174  // Left normalization of boundaries representation
175  this->approximation_interval.lower_bound.normalize_left();
176  this->approximation_interval.upper_bound.normalize_left();
177 
178  this->check_and_swap_boundaries();
179  this->_n = std::min(this->_n + n, (int)this->_real_ptr->_digits.size());
180  }
181 
189  bool operator==(const const_precision_iterator& other) const {
190  // uninitialized iterators are never equals
191  if (this->_real_ptr == nullptr || other._real_ptr == nullptr) {
192  return false;
193  }
194 
195  return (other._real_ptr == this->_real_ptr) &&
196  (other._n == this->_n) &&
197  (other.approximation_interval == this->approximation_interval);
198  }
199 
206  bool operator!=(const const_precision_iterator& other) const {
207  return !(*this == other);
208  }
209  };
210 
215  real_explicit() = default;
216 
222  real_explicit(const real_explicit& other) = default;
223 
233  explicit real_explicit(const std::string& number) {
234  // Check that is not an empty string
235  if (number.length() == 0) {
237  }
238 
239  // Check that there is no more that one '.' symbol
240  unsigned int dot_amount = 0;
241  for (const auto& c : number ) {
242  if (c == '.' && dot_amount >= 1) {
244  } else if (c == '.') {
245  dot_amount++;
246  }
247  }
248 
249  bool there_is_dot = dot_amount > 0;
250  int exponent = 0;
251  dot_amount = 0;
252 
253  // Check whether the number is explicitly specified as positive or negative
254  unsigned int first_index = 0;
255  if (number.at(first_index) == '+') {
256  this->_positive = true;
257  first_index++;
258  } else if (number.at(first_index) == '-') {
259  this->_positive = false;
260  first_index++;
261  }
262 
263  // Remove zeros from the lefts side
264  // Note: We know at this point that number.length > 0 because the first check
265  unsigned int last_index = (unsigned int)number.length() - 1;
266  while (last_index > first_index && (number.at(last_index) == '0' || number.at(last_index) == '.')) {
267  if (number.at(last_index) == '.') {
268  dot_amount++;
269  }
270  last_index--;
271  if (!there_is_dot || dot_amount > 0) {
272  exponent++; // remove zeros from the integer part increases the exponent
273  }
274  }
275 
276  // The number is all composed by zeros, then it is zero
277  if (last_index == first_index && number.at(last_index) == '0') {
278  this->_digits = {0};
279  this->_exponent = 0;
280  return;
281  }
282 
283  // Remove zeros from the right side
284  // Note: if the number is all made by zeros, then the code never reaches this part
285  // This is why we don't need to check that first_index is lower than the string length
286  while (number.at(first_index) == '0') {
287  first_index++;
288  }
289 
290  if (number.at(first_index) == '.') {
291  dot_amount++;
292  first_index++;
293  while (number.at(first_index) == '0') {
294  first_index++;
295  exponent--;
296  }
297  }
298 
299  for (unsigned int i = first_index; i <= last_index; i++) {
300 
301  if (number.at(i) == '.') {
302  dot_amount++;
303 
304  } else {
305  // This will only affect if the '.' appears, in that case, exponent
306  // wasn't negative and no inconsistency is made.
307  if (dot_amount == 0) exponent++;
308  try {
309  this->_digits.push_back(number.at(i) - '0');
310  } catch (const std::invalid_argument& e) {
312  }
313 
314  }
315  }
316 
317  this->_exponent = exponent;
318  this->_maximum_precision = (int)this->_digits.size();
319  };
320 
330  real_explicit(std::initializer_list<int> digits, int exponent) :
331  _digits(digits),
332  _exponent(exponent),
333  _maximum_precision((int)this->_digits.size())
334  {};
335 
348  real_explicit(std::initializer_list<int> digits, int exponent, bool positive):
349  _digits(digits),
350  _exponent(exponent),
351  _positive(positive),
352  _maximum_precision((int)this->_digits.size())
353  {};
354 
361  unsigned int max_precision() const {
362  return this->_maximum_precision;
363  }
364 
370  void set_maximum_precision(unsigned int maximum_precision) {
371  this->_maximum_precision = maximum_precision;
372  }
373 
377  int exponent() const {
378  return this->_exponent;
379  }
380 
384  bool positive() const {
385  return this->_positive;
386  }
387 
391  const std::vector<int>& digits() const {
392  return this->_digits;
393  }
394 
404  return const_precision_iterator(this);
405  }
406 
416  const_precision_iterator it(this);
417  it.iterate_n_times((int)this->_digits.size() + 1);
418  return it;
419  }
420 
427  int operator[](unsigned int n) const {
428  if (n < this->_digits.size()) {
429  return this->_digits.at(n);
430  }
431 
432  return 0;
433  }
434 
441  real_explicit& operator=(const real_explicit& other) = default;
442  };
443  }
444 }
445 
453 std::ostream& operator<<(std::ostream& os, const boost::real::real_explicit& r) {
454  auto it = r.cbegin();
455  for (unsigned int i = 0; i <= r.max_precision(); i++) {
456  ++it;
457  }
458  os << it.approximation_interval;
459  return os;
460 }
461 
462 
463 #endif //BOOST_REAL_REAL_EXPLICIT_HPP
bool positive() const
Definition: real_explicit.hpp:384
void iterate_n_times(int n)
It recalculates the approximation interval boundaries increasing the used precision n times...
Definition: real_explicit.hpp:118
boost::real::real_explicit is a C++ class that fully represents real numbers as a vector of digits...
Definition: real_explicit.hpp:22
Definition: boundary.hpp:7
int operator[](unsigned int n) const
Returns the n-th digit the number.
Definition: real_explicit.hpp:427
is a forward iterator that iterates a boost::real::real_explicit number approximation intervals...
Definition: real_explicit.hpp:42
real_explicit(const std::string &number)
String constructor: Creates a boost::real::real_explicit instance by parsing the string. The string must have a valid number, in other case, the constructor will throw an boost::real::invalid_string_number exception.
Definition: real_explicit.hpp:233
void clear()
ir clears the number digits.
Definition: boundary.hpp:235
const_precision_iterator(real_explicit const *real_number)
Pointer constructor: Construct a new boost::real::real_explicit::const_precision_iterator pointing to...
Definition: real_explicit.hpp:85
void operator++()
It recalculates the approximation interval boundaries increasing the used precision, the new pointed approximation interval is smaller than the current one.
Definition: real_explicit.hpp:110
Represent an interval composed by two boundaries, a lower boundary and an upper boundary. The boundaries are boost::real::boundary structs that represent fully represented numbers.
Definition: interval.hpp:18
int exponent() const
Definition: real_explicit.hpp:377
real_explicit(std::initializer_list< int > digits, int exponent, bool positive)
Initializer list constructor with exponent and sign: Creates a boost::real::real_explicit instance th...
Definition: real_explicit.hpp:348
void push_front(int digit)
add the digit parameter as a new digit of the boost::real::boundary. The digit is added in the left s...
Definition: boundary.hpp:196
bool operator!=(const const_precision_iterator &other) const
It compare by value not equal; two boost::real::real_explicit::const_precision_iterators.
Definition: real_explicit.hpp:206
real_explicit()=default
Default constructor: Construct an empty boost::real::real_explicit with undefined representation and ...
void push_back(int digit)
add the digit parameter as a new digit of the boost::real::boundary. The digit is added in the right ...
Definition: boundary.hpp:186
const_precision_iterator cbegin() const
Construct a new boost::real::real_explicit::const_precision_iterator that iterates the number approxi...
Definition: real_explicit.hpp:403
const_precision_iterator()=default
Default constructor: Constructs an empty boost::real::real_explicit::const_precision_iterator that po...
unsigned int max_precision() const
Returns te maximum allowed precision, if that precision is reached and an operator need more precisio...
Definition: real_explicit.hpp:361
void set_maximum_precision(unsigned int maximum_precision)
Set a new maximum precision for the instance.
Definition: real_explicit.hpp:370
real_explicit(std::initializer_list< int > digits, int exponent)
Initializer list constructor with exponent: Creates a boost::real::real_explicit instance that repres...
Definition: real_explicit.hpp:330
void normalize_left()
Removes extra zeros at the left side to convert the number representation into a semi normalized repr...
Definition: boundary.hpp:225
void swap_bounds()
Swaps the lower boundary with the upper boundary. After this method is called the boost::real::interv...
Definition: interval.hpp:52
const_precision_iterator cend() const
Construct a new boost::real::real_explicit::const_precision_iterator that iterates the number approxi...
Definition: real_explicit.hpp:415
Definition: real_exception.hpp:29
const std::vector< int > & digits() const
Definition: real_explicit.hpp:391
unsigned long size()
It return the amount of digit of the boost::real::boundary.
Definition: boundary.hpp:254
bool operator==(const const_precision_iterator &other) const
It compare by value equality; two boost::real::real_explicit::const_precision_iterators are equals if...
Definition: real_explicit.hpp:189
real_explicit & operator=(const real_explicit &other)=default
It assign a new copy of the other boost::real::real_explicit number in the *this boost::real::real_ex...