Boost.Real  1.0.0
Boost.Real numerical data type for real numbers representation using range arithmetic.
real.hpp
1 #ifndef BOOST_REAL_REAL_HPP
2 #define BOOST_REAL_REAL_HPP
3 
4 #include <iostream>
5 #include <vector>
6 #include <algorithm>
7 #include <initializer_list>
8 #include <utility>
9 
10 #include <real/real_exception.hpp>
11 #include <real/real_helpers.hpp>
12 #include <real/real_explicit.hpp>
13 #include <real/real_algorithm.hpp>
14 
15 
16 namespace boost {
17  namespace real {
18 
54  class real {
55 
56  // Available operations
57  enum class OPERATION {ADDITION, SUBTRACT, MULTIPLICATION};
58  enum class KIND {EXPLICIT, OPERATION, ALGORITHM};
59 
60  KIND _kind;
61 
62  // Explicit number
63  real_explicit _explicit_number;
64 
65  // Algorithmic number
66  real_algorithm _algorithmic_number;
67 
68  // Composed number
69  OPERATION _operation;
70  real* _lhs_ptr = nullptr;
71  real* _rhs_ptr = nullptr;
72 
73  // Precision
74  unsigned int _maximum_precision = 0;
75 
76  void copy_operands(const real& other) {
77  if (other._lhs_ptr != nullptr) {
78  this->_lhs_ptr = new real(*other._lhs_ptr);
79  }
80 
81  if (other._rhs_ptr != nullptr) {
82  this->_rhs_ptr = new real(*other._rhs_ptr);
83  }
84  }
85 
86  public:
87 
91  static unsigned int maximum_precision;
92 
101  private:
102 
103  // Internal number to iterate
104  real const* _real_ptr = nullptr;
105 
106  // Explicit number iterator
108 
109  // Algorithmic number iterator
111 
112  // If the number is a composition, the const_precision_iterator uses the operand iterators
113  const_precision_iterator* _lhs_it_ptr = nullptr;
114  const_precision_iterator* _rhs_it_ptr = nullptr;
115 
116  void calculate_operation_boundaries() {
117 
118  switch (this->_real_ptr->_operation) {
119 
120  case OPERATION::ADDITION:
121  boost::real::helper::add_boundaries(
122  this->_lhs_it_ptr->approximation_interval.lower_bound,
123  this->_rhs_it_ptr->approximation_interval.lower_bound,
124  this->approximation_interval.lower_bound
125  );
126 
127  boost::real::helper::add_boundaries(
128  this->_lhs_it_ptr->approximation_interval.upper_bound,
129  this->_rhs_it_ptr->approximation_interval.upper_bound,
130  this->approximation_interval.upper_bound
131  );
132  break;
133 
134 
135  case OPERATION::SUBTRACT:
136  boost::real::helper::subtract_boundaries(
137  this->_lhs_it_ptr->approximation_interval.lower_bound,
138  this->_rhs_it_ptr->approximation_interval.upper_bound,
139  this->approximation_interval.lower_bound
140  );
141 
142  boost::real::helper::subtract_boundaries(
143  this->_lhs_it_ptr->approximation_interval.upper_bound,
144  this->_rhs_it_ptr->approximation_interval.lower_bound,
145  this->approximation_interval.upper_bound
146  );
147  break;
148 
149 
150  case OPERATION::MULTIPLICATION: {
151  bool lhs_positive = this->_lhs_it_ptr->approximation_interval.positive();
152  bool rhs_positive = this->_rhs_it_ptr->approximation_interval.positive();
153  bool lhs_negative = this->_lhs_it_ptr->approximation_interval.negative();
154  bool rhs_negative = this->_rhs_it_ptr->approximation_interval.negative();
155 
156  if (lhs_positive && rhs_positive) { // Positive - Positive
157  boost::real::helper::multiply_boundaries(
158  this->_lhs_it_ptr->approximation_interval.lower_bound,
159  this->_rhs_it_ptr->approximation_interval.lower_bound,
160  this->approximation_interval.lower_bound
161  );
162 
163  boost::real::helper::multiply_boundaries(
164  this->_lhs_it_ptr->approximation_interval.upper_bound,
165  this->_rhs_it_ptr->approximation_interval.upper_bound,
166  this->approximation_interval.upper_bound
167  );
168 
169  } else if (lhs_negative && rhs_negative) { // Negative - Negative
170  boost::real::helper::multiply_boundaries(
171  this->_lhs_it_ptr->approximation_interval.upper_bound,
172  this->_rhs_it_ptr->approximation_interval.upper_bound,
173  this->approximation_interval.lower_bound
174  );
175 
176  boost::real::helper::multiply_boundaries(
177  this->_lhs_it_ptr->approximation_interval.lower_bound,
178  this->_rhs_it_ptr->approximation_interval.lower_bound,
179  this->approximation_interval.upper_bound
180  );
181  } else if (lhs_negative && rhs_positive) { // Negative - Positive
182  boost::real::helper::multiply_boundaries(
183  this->_lhs_it_ptr->approximation_interval.lower_bound,
184  this->_rhs_it_ptr->approximation_interval.upper_bound,
185  this->approximation_interval.lower_bound
186  );
187 
188  boost::real::helper::multiply_boundaries(
189  this->_lhs_it_ptr->approximation_interval.upper_bound,
190  this->_rhs_it_ptr->approximation_interval.lower_bound,
191  this->approximation_interval.upper_bound
192  );
193 
194  } else if (lhs_positive && rhs_negative) { // Positive - Negative
195  boost::real::helper::multiply_boundaries(
196  this->_lhs_it_ptr->approximation_interval.upper_bound,
197  this->_rhs_it_ptr->approximation_interval.lower_bound,
198  this->approximation_interval.lower_bound
199  );
200 
201  boost::real::helper::multiply_boundaries(
202  this->_lhs_it_ptr->approximation_interval.lower_bound,
203  this->_rhs_it_ptr->approximation_interval.upper_bound,
204  this->approximation_interval.upper_bound
205  );
206 
207  } else { // One is around zero all possible combinations are be tested
208 
209  boundary current_boundary;
210 
211  // Lower * Lower
212  boost::real::helper::multiply_boundaries(
213  this->_lhs_it_ptr->approximation_interval.lower_bound,
214  this->_rhs_it_ptr->approximation_interval.lower_bound,
215  current_boundary
216  );
217 
218  this->approximation_interval.lower_bound = current_boundary;
219  this->approximation_interval.upper_bound = current_boundary;
220 
221  // Upper * upper
222  boost::real::helper::multiply_boundaries(
223  this->_lhs_it_ptr->approximation_interval.upper_bound,
224  this->_rhs_it_ptr->approximation_interval.upper_bound,
225  current_boundary
226  );
227 
228  if (current_boundary < this->approximation_interval.lower_bound) {
229  this->approximation_interval.lower_bound = current_boundary;
230  }
231 
232  if (this->approximation_interval.upper_bound < current_boundary) {
233  this->approximation_interval.upper_bound = current_boundary;
234  }
235 
236  // Lower * upper
237  boost::real::helper::multiply_boundaries(
238  this->_lhs_it_ptr->approximation_interval.lower_bound,
239  this->_rhs_it_ptr->approximation_interval.upper_bound,
240  current_boundary
241  );
242 
243  if (current_boundary < this->approximation_interval.lower_bound) {
244  this->approximation_interval.lower_bound = current_boundary;
245  }
246 
247  if (this->approximation_interval.upper_bound < current_boundary) {
248  this->approximation_interval.upper_bound = current_boundary;
249  }
250 
251  // Upper * lower
252  boost::real::helper::multiply_boundaries(
253  this->_lhs_it_ptr->approximation_interval.upper_bound,
254  this->_rhs_it_ptr->approximation_interval.lower_bound,
255  current_boundary
256  );
257 
258  if (current_boundary < this->approximation_interval.lower_bound) {
259  this->approximation_interval.lower_bound = current_boundary;
260  }
261 
262  if (this->approximation_interval.upper_bound < current_boundary) {
263  this->approximation_interval.upper_bound = current_boundary;
264  }
265  }
266  break;
267  }
268 
269  default:
271  }
272  }
273 
274  public:
275 
276  // Number approximation_interval boundaries
277  boost::real::interval approximation_interval;
278 
283  const_precision_iterator() = default;
284 
291  const_precision_iterator(const const_precision_iterator& other) = default;
292 
301  explicit const_precision_iterator(real const* real_number) : _real_ptr(real_number) {
302 
303  switch (this->_real_ptr->_kind) {
304 
305  case KIND::EXPLICIT:
306  this->_explicit_it = this->_real_ptr->_explicit_number.cbegin();
307  this->approximation_interval = this->_explicit_it.approximation_interval;
308  break;
309 
310  case KIND::ALGORITHM:
311  this->_algorithmic_it = this->_real_ptr->_algorithmic_number.cbegin();
312  this->approximation_interval = this->_algorithmic_it.approximation_interval;
313  break;
314 
315  case KIND::OPERATION:
316  this->_lhs_it_ptr = new const_precision_iterator(this->_real_ptr->_lhs_ptr->cbegin());
317  this->_rhs_it_ptr = new const_precision_iterator(this->_real_ptr->_rhs_ptr->cbegin());
318  this->calculate_operation_boundaries();
319  break;
320  }
321  }
322 
336  explicit const_precision_iterator(real const* real_number, bool cend) : _real_ptr(real_number) {
337 
338  switch (this->_real_ptr->_kind) {
339 
340  case KIND::EXPLICIT:
341  if (cend) {
342  this->_explicit_it = this->_real_ptr->_explicit_number.cend();
343  } else {
344  this->_explicit_it = this->_real_ptr->_explicit_number.cbegin();
345  }
346  this->approximation_interval = this->_explicit_it.approximation_interval;
347  break;
348 
349  case KIND::ALGORITHM:
350  if (cend) {
351  this->_algorithmic_it = this->_real_ptr->_algorithmic_number.cend();
352  } else {
353  this->_algorithmic_it = this->_real_ptr->_algorithmic_number.cbegin();
354  }
355  this->approximation_interval = this->_algorithmic_it.approximation_interval;
356  break;
357 
358  case KIND::OPERATION:
359  this->_lhs_it_ptr = new const_precision_iterator(this->_real_ptr->_lhs_ptr, cend);
360  this->_rhs_it_ptr = new const_precision_iterator(this->_real_ptr->_rhs_ptr, cend);
361  this->calculate_operation_boundaries();
362  break;
363  }
364  }
365 
370  void operator++() {
371 
372  switch (this->_real_ptr->_kind) {
373 
374  case KIND::EXPLICIT:
375  ++this->_explicit_it;
376  this->approximation_interval = this->_explicit_it.approximation_interval;
377  break;
378 
379  case KIND::ALGORITHM:
380  ++this->_algorithmic_it;
381  this->approximation_interval = this->_algorithmic_it.approximation_interval;
382  break;
383 
384  case KIND::OPERATION:
385  // Composed number iteration
386  this->approximation_interval.lower_bound.clear();
387  this->approximation_interval.upper_bound.clear();
388 
389  // Recursive iteration of the operands
390  ++(*this->_lhs_it_ptr);
391  ++(*this->_rhs_it_ptr);
392 
393  // Final bound calculation
394  this->calculate_operation_boundaries();
395  break;
396  }
397  };
398 
406  bool operator==(const const_precision_iterator& other) const {
407  // uninitialized iterators are never equals
408  if (this->_real_ptr == nullptr || other._real_ptr == nullptr) {
409  return false;
410  }
411 
412  return (other._real_ptr == this->_real_ptr) && (other.approximation_interval == this->approximation_interval);
413  }
414 
421  bool operator!=(const const_precision_iterator& other) const {
422  return !(*this == other);
423  }
424  };
425 
432  real() = default;
433 
441  real(const real& other) :
442  _kind(other._kind),
443  _explicit_number(other._explicit_number),
444  _algorithmic_number(other._algorithmic_number),
445  _operation(other._operation) { this->copy_operands(other); };
446 
456  real(const std::string& number)
457  : _kind(KIND::EXPLICIT), _explicit_number(number) {}
458 
466  real(std::initializer_list<int> digits)
467  : _kind(KIND::EXPLICIT), _explicit_number(digits, digits.size()) {}
468 
469 
480  real(std::initializer_list<int> digits, bool positive)
481  : _kind(KIND::EXPLICIT), _explicit_number(digits, digits.size(), positive) {}
482 
492  real(std::initializer_list<int> digits, int exponent)
493  : _kind(KIND::EXPLICIT), _explicit_number(digits, exponent) {};
494 
506  real(std::initializer_list<int> digits, int exponent, bool positive)
507  : _kind(KIND::EXPLICIT), _explicit_number(digits, exponent, positive) {};
508 
519  real(int (*get_nth_digit)(unsigned int), int exponent)
520  : _kind(KIND::ALGORITHM), _algorithmic_number(get_nth_digit, exponent) {}
521 
535  real(int (*get_nth_digit)(unsigned int),
536  int exponent,
537  bool positive)
538  : _kind(KIND::ALGORITHM),
539  _algorithmic_number(get_nth_digit, exponent, positive) {}
540 
544  ~real() {
545  delete this->_lhs_ptr;
546  this->_lhs_ptr = nullptr;
547 
548  delete this->_rhs_ptr;
549  this->_rhs_ptr = nullptr;
550  }
551 
558  unsigned int max_precision() const {
559  if (this->_maximum_precision == 0) {
561  }
562 
563  return this->_maximum_precision;
564  }
565 
574  void set_maximum_precision(unsigned int maximum_precision) {
575  this->_maximum_precision = maximum_precision;
576  }
577 
587  return const_precision_iterator(this);
588  }
589 
599  return const_precision_iterator(this, true);
600  }
601 
602  /************** Operators ******************/
603 
613  int operator[](unsigned int n) const {
614  int result;
615 
616  switch (this->_kind) {
617 
618  case KIND::EXPLICIT:
619  result = this->_explicit_number[n];
620  break;
621 
622  case KIND::ALGORITHM:
623  result = this->_algorithmic_number[n];
624  break;
625 
626  case KIND::OPERATION:
628  break;
629  }
630 
631  return result;
632  };
633 
642  real& operator+=(const real& other) {
643  this->_lhs_ptr = new real(*this);
644  this->_rhs_ptr = new real(other);
645  this->_kind = KIND::OPERATION;
646  this->_operation = OPERATION::ADDITION;
647  return *this;
648  }
649 
658  real operator+(const real& other) const {
659  real result = *this;
660  result += other;
661  return result;
662  }
663 
672  real& operator-=(const real& other) {
673  this->_lhs_ptr = new real(*this);
674  this->_rhs_ptr = new real(other);
675  this->_kind = KIND::OPERATION;
676  this->_operation = OPERATION::SUBTRACT;
677  return *this;
678  }
679 
688  real operator-(const real& other) const {
689  real result = *this;
690  result -= other;
691  return result;
692  }
693 
702  real& operator*=(const real& other) {
703  this->_lhs_ptr = new real(*this);
704  this->_rhs_ptr = new real(other);
705  this->_kind = KIND::OPERATION;
706  this->_operation = OPERATION::MULTIPLICATION;
707  return *this;
708  }
709 
718  real operator*(const real& other) const {
719  real result = *this;
720  result *= other;
721  return result;
722  }
723 
730  real& operator=(const real& other) {
731  this->_kind = other._kind;
732  this->_explicit_number = other._explicit_number;
733  this->_operation = other._operation;
734  this->copy_operands(other);
735  return *this;
736  }
737 
745  real& operator=(const std::string& number) {
746  *this = real(number);
747  return *this;
748  }
749 
761  bool operator<(const real& other) const {
762  auto this_it = this->cbegin();
763  auto other_it = other.cbegin();
764 
765  unsigned int current_precision = std::max(this->max_precision(), other.max_precision());
766  for (unsigned int p = 0; p < current_precision; ++p) {
767  // Get more precision
768  ++this_it;
769  ++other_it;
770 
771  bool this_full_precision = this_it.approximation_interval.is_a_number();
772  bool other_full_precision = other_it.approximation_interval.is_a_number();
773  if (this_full_precision && other_full_precision) {
774  return this_it.approximation_interval < other_it.approximation_interval;
775  }
776 
777  if (this_it.approximation_interval < other_it.approximation_interval) {
778  return true;
779  }
780 
781  if (other_it.approximation_interval < this_it.approximation_interval) {
782  return false;
783  }
784  }
785 
786  // If the precision is reached and the number ranges still overlap, then we cannot
787  // know if they are equals or other is less than this and we throw an error.
789  }
790 
802  bool operator>(const real& other) const {
803  auto this_it = this->cbegin();
804  auto other_it = other.cbegin();
805 
806  unsigned int current_precision = std::max(this->max_precision(), other.max_precision());
807  for (unsigned int p = 0; p < current_precision; ++p) {
808  // Get more precision
809  ++this_it;
810  ++other_it;
811 
812  bool this_full_precision = this_it.approximation_interval.is_a_number();
813  bool other_full_precision = other_it.approximation_interval.is_a_number();
814  if (this_full_precision && other_full_precision) {
815  return this_it.approximation_interval > other_it.approximation_interval;
816  }
817 
818  if (this_it.approximation_interval > other_it.approximation_interval) {
819  return true;
820  }
821 
822  if (other_it.approximation_interval > this_it.approximation_interval) {
823  return false;
824  }
825  }
826 
827  // If the precision is reached and the number ranges still overlap, then we cannot
828  // know if they are equals or other is less than this and we throw an error.
830  }
831 
843  bool operator==(const real& other) const {
844  auto this_it = this->cbegin();
845  auto other_it = other.cbegin();
846 
847  unsigned int current_precision = std::max(this->max_precision(), other.max_precision());
848  for (unsigned int p = 0; p < current_precision; ++p) {
849  // Get more precision
850  ++this_it;
851  ++other_it;
852 
853  bool this_full_precision = this_it.approximation_interval.is_a_number();
854  bool other_full_precision = other_it.approximation_interval.is_a_number();
855  if (this_full_precision && other_full_precision) {
856  return this_it.approximation_interval == other_it.approximation_interval;
857  }
858 
859  bool this_is_lower = this_it.approximation_interval < other_it.approximation_interval;
860  bool other_is_lower = other_it.approximation_interval < this_it.approximation_interval;
861  if (this_is_lower || other_is_lower) {
862  return false;
863  }
864  }
865 
866  // If the precision is reached and the numbers full precision is not reached, then
867  // we cannot know if they are equals or not.
869  }
870  };
871  }
872 }
873 
881 std::ostream& operator<<(std::ostream& os, const boost::real::real& r) {
882  os << r.cend().approximation_interval;
883  return os;
884 }
885 
886 #endif //BOOST_REAL_REAL_HPP
real(int(*get_nth_digit)(unsigned int), int exponent)
Lambda function constructor with exponent: Creates a boost::real::real instance that represents the n...
Definition: real.hpp:519
Definition: real_exception.hpp:8
Definition: real_exception.hpp:22
boost::real::real_explicit is a C++ class that fully represents real numbers as a vector of digits...
Definition: real_explicit.hpp:22
real operator-(const real &other) const
Creates a new boost::real::real representing an operation number where the operands are copies of the...
Definition: real.hpp:688
Definition: boundary.hpp:7
is a forward iterator that iterates a boost::real::real_algorithm number approximation intervals...
Definition: real_algorithm.hpp:41
real(int(*get_nth_digit)(unsigned int), int exponent, bool positive)
Lambda function constructor with exponent and sign: Creates a boost::real::real instance that represe...
Definition: real.hpp:535
bool operator==(const real &other) const
Compares the *this boost::real::real number against the other boost::real::real number to determine i...
Definition: real.hpp:843
is a forward iterator that iterates a boost::real::real_explicit number approximation intervals...
Definition: real_explicit.hpp:42
~real()
Default destructor: If the number is an operator, the destructor destroys its operands.
Definition: real.hpp:544
const_precision_iterator(real const *real_number)
Pointer constructor: Construct a new boost::real::real::const_precision_iterator pointing to the boos...
Definition: real.hpp:301
Definition: real_exception.hpp:15
const_precision_iterator(real const *real_number, bool cend)
Pointer constructor for cend: Construct a new boost::real::real::const_precision_iterator pointing to...
Definition: real.hpp:336
real(std::initializer_list< int > digits, int exponent)
Initializer list constructor with exponent: Creates a boost::real::real instance that represents the ...
Definition: real.hpp:492
void clear()
ir clears the number digits.
Definition: boundary.hpp:235
real operator+(const real &other) const
Creates a new boost::real::real representing an operation number where the operands are copies of the...
Definition: real.hpp:658
boost::real::real_algorithm is a C++ class that represents real numbers as a a function that calculat...
Definition: real_algorithm.hpp:19
real & operator=(const std::string &number)
It constructs and boost::real::real number from the std::string and assign it in the *this boost::rea...
Definition: real.hpp:745
bool operator==(const const_precision_iterator &other) const
It compare by value equality; two boost::real::real::const_precision_iterators are equals if they are...
Definition: real.hpp:406
real & operator+=(const real &other)
Convert the number from its current representation to an operation number representation where the op...
Definition: real.hpp:642
real(const std::string &number)
String constructor: Creates a boost::real::real instance by parsing the string. The string must have ...
Definition: real.hpp:456
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
bool operator<(const real &other) const
Compares the *this boost::real::real number against the other boost::real::real number to determine i...
Definition: real.hpp:761
real & operator*=(const real &other)
Convert the number from its current representation to an operation number representation where the op...
Definition: real.hpp:702
real(std::initializer_list< int > digits, int exponent, bool positive)
Initializer list constructor with exponent and sign: Creates a boost::real::real instance that repres...
Definition: real.hpp:506
const_precision_iterator cbegin() const
Construct a new boost::real::real::con_precision_iterator that iterates the number approximation inte...
Definition: real.hpp:586
bool positive() const
Determine if the interval is fully contained in the positive real number line.
Definition: interval.hpp:85
unsigned int max_precision() const
Returns te maximum allowed precision, if that precision is reached and an operator need more precisio...
Definition: real.hpp:558
real(std::initializer_list< int > digits, bool positive)
Signed initializer list constructor: Creates a boost::real::real instance that represents the number ...
Definition: real.hpp:480
boost::real::real is a C++ class that represent real numbers as abstract entities that can be dynamic...
Definition: real.hpp:54
real(std::initializer_list< int > digits)
Initializer list constructor: Creates a boost::real::real_explicit instance that represents an intege...
Definition: real.hpp:466
bool operator>(const real &other) const
Compares the *this boost::real::real number against the other boost::real::real number to determine i...
Definition: real.hpp:802
bool negative() const
Determine if the interval is fully contained in the negative real number line.
Definition: interval.hpp:96
const_precision_iterator cend() const
Construct a new boost::real::real::con_precision_iterator that iterates the number approximation inte...
Definition: real.hpp:598
bool operator!=(const const_precision_iterator &other) const
It compare by value not equal; two boost::real::real::const_precision_iterators.
Definition: real.hpp:421
real operator*(const real &other) const
Creates a new boost::real::real representing an operation number where the operands are copies of the...
Definition: real.hpp:718
void set_maximum_precision(unsigned int maximum_precision)
Set a new maximum precision for the instance.
Definition: real.hpp:574
real()=default
Default constructor: Constructr a boost::real::real with undefined representation and behaviour...
real & operator=(const real &other)
It assign a new copy of the other boost::real::real number in the *this boost::real::real number...
Definition: real.hpp:730
is a forward iterator that iterates a boost::real::real number approximation intervals. The iterator calculates the initial interval with the initial precision and then it increase the precision in each iteration (++) and recalculate the interval.
Definition: real.hpp:100
Explicitly represents a number as a vector of digits with a sign and an exponent. ...
Definition: boundary.hpp:15
real & operator-=(const real &other)
Convert the number from its current representation to an operation number representation where the op...
Definition: real.hpp:672
static unsigned int maximum_precision
Determines the maximum precision to use.
Definition: real.hpp:91
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.hpp:370
real(const real &other)
Copy constructor: Creates a copy of the boost::real::real number other, if the number is an operation...
Definition: real.hpp:441
int operator[](unsigned int n) const
If the number is an explicit or algorithm number it returns the n-th digit of the represented number...
Definition: real.hpp:613