rational.h
Go to the documentation of this file.
1 
6 #ifndef SYMENGINE_RATIONAL_H
7 #define SYMENGINE_RATIONAL_H
8 
9 #include <symengine/constants.h>
10 #include <symengine/symengine_exception.h>
11 
12 namespace SymEngine
13 {
15 class Rational : public Number
16 {
17 private:
19  rational_class i;
20 
21 public:
22  IMPLEMENT_TYPEID(SYMENGINE_RATIONAL)
24  Rational(rational_class &&_i) : i(std::move(_i))
25  {
26  SYMENGINE_ASSIGN_TYPEID()
27  }
31  static RCP<const Number> from_mpq(const rational_class &i);
32  static RCP<const Number> from_mpq(rational_class &&i);
34  virtual hash_t __hash__() const;
39  virtual bool __eq__(const Basic &o) const;
40  virtual int compare(const Basic &o) const;
42  bool is_canonical(const rational_class &i) const;
43 
47  static RCP<const Number> from_two_ints(const Integer &n, const Integer &d);
48  static RCP<const Number> from_two_ints(const long n, const long d);
50  inline const rational_class &as_rational_class() const
51  {
52  return this->i;
53  }
55  virtual bool is_zero() const
56  {
57  return this->i == 0;
58  }
60  virtual bool is_one() const
61  {
62  return this->i == 1;
63  }
65  virtual bool is_minus_one() const
66  {
67  return this->i == -1;
68  }
70  inline bool is_int() const
71  {
72  return this->i == 1;
73  }
75  inline virtual bool is_positive() const
76  {
77  return i > 0;
78  }
80  inline virtual bool is_negative() const
81  {
82  return i < 0;
83  }
85  // False is returned because a rational cannot have an imaginary part
86  inline virtual bool is_complex() const
87  {
88  return false;
89  }
90 
92  inline RCP<const Rational> neg() const
93  {
94  return make_rcp<const Rational>(-i);
95  }
96 
97  virtual bool is_perfect_power(bool is_expected = false) const;
98  // \return true if there is a exact nth root of self.
99  virtual bool nth_root(const Ptr<RCP<const Number>> &,
100  unsigned long n) const;
101 
105  inline RCP<const Number> addrat(const Rational &other) const
106  {
107  return from_mpq(this->i + other.i);
108  }
112  inline RCP<const Number> addrat(const Integer &other) const
113  {
114  return from_mpq(this->i + other.as_integer_class());
115  }
119  inline RCP<const Number> subrat(const Rational &other) const
120  {
121  return from_mpq(this->i - other.i);
122  }
126  inline RCP<const Number> subrat(const Integer &other) const
127  {
128  return from_mpq(this->i - other.as_integer_class());
129  }
130  inline RCP<const Number> rsubrat(const Integer &other) const
131  {
132  return from_mpq(other.as_integer_class() - this->i);
133  }
137  inline RCP<const Number> mulrat(const Rational &other) const
138  {
139  return from_mpq(this->i * other.i);
140  }
144  inline RCP<const Number> mulrat(const Integer &other) const
145  {
146  return from_mpq(this->i * other.as_integer_class());
147  }
151  inline RCP<const Number> divrat(const Rational &other) const
152  {
153  if (other.i == 0) {
154  if (this->i == 0) {
155  return Nan;
156  } else {
157  return ComplexInf;
158  }
159  } else {
160  return from_mpq(this->i / other.i);
161  }
162  }
166  inline RCP<const Number> divrat(const Integer &other) const
167  {
168  if (other.as_integer_class() == 0) {
169  if (this->i == 0) {
170  return Nan;
171  } else {
172  return ComplexInf;
173  }
174  } else {
175  return from_mpq(this->i / other.as_integer_class());
176  }
177  }
178  inline RCP<const Number> rdivrat(const Integer &other) const
179  {
180  if (this->i == 0) {
181  if (other.is_zero()) {
182  return Nan;
183  } else {
184  return ComplexInf;
185  }
186  } else {
187  return from_mpq(other.as_integer_class() / this->i);
188  }
189  }
193  inline RCP<const Number> powrat(const Integer &other) const
194  {
195  bool neg = other.is_negative();
196  integer_class exp_ = other.as_integer_class();
197  if (neg)
198  exp_ = -exp_;
199  if (not mp_fits_ulong_p(exp_))
200  throw SymEngineException("powrat: 'exp' does not fit ulong.");
201  unsigned long exp = mp_get_ui(exp_);
202 
203 #if SYMENGINE_INTEGER_CLASS == SYMENGINE_BOOSTMP
204  // boost::multiprecision::cpp_rational doesn't provide
205  // non-const references to num and den
206  integer_class num;
207  integer_class den;
208  mp_pow_ui(num, SymEngine::get_num(i), exp);
209  mp_pow_ui(den, SymEngine::get_den(i), exp);
210  rational_class val(num, den);
211 #else
212  rational_class val;
213  mp_pow_ui(SymEngine::get_num(val), SymEngine::get_num(i), exp);
214  mp_pow_ui(SymEngine::get_den(val), SymEngine::get_den(i), exp);
215 #endif
216 
217  // Since 'this' is in canonical form, so is this**other, so we simply
218  // pass val into the constructor directly without canonicalizing:
219  if (not neg) {
220  return Rational::from_mpq(std::move(val));
221  } else {
222  return Rational::from_mpq(1 / val);
223  }
224  }
228  RCP<const Basic> powrat(const Rational &other) const;
233  RCP<const Basic> rpowrat(const Integer &other) const;
234 
236  virtual RCP<const Number> add(const Number &other) const
237  {
238  if (is_a<Rational>(other)) {
239  return addrat(down_cast<const Rational &>(other));
240  } else if (is_a<Integer>(other)) {
241  return addrat(down_cast<const Integer &>(other));
242  } else {
243  return other.add(*this);
244  }
245  };
247  virtual RCP<const Number> sub(const Number &other) const
248  {
249  if (is_a<Rational>(other)) {
250  return subrat(down_cast<const Rational &>(other));
251  } else if (is_a<Integer>(other)) {
252  return subrat(down_cast<const Integer &>(other));
253  } else {
254  return other.rsub(*this);
255  }
256  };
258  virtual RCP<const Number> rsub(const Number &other) const
259  {
260  if (is_a<Integer>(other)) {
261  return rsubrat(down_cast<const Integer &>(other));
262  } else {
263  throw NotImplementedError("Not Implemented");
264  }
265  };
267  virtual RCP<const Number> mul(const Number &other) const
268  {
269  if (is_a<Rational>(other)) {
270  return mulrat(down_cast<const Rational &>(other));
271  } else if (is_a<Integer>(other)) {
272  return mulrat(down_cast<const Integer &>(other));
273  } else {
274  return other.mul(*this);
275  }
276  };
278  virtual RCP<const Number> div(const Number &other) const
279  {
280  if (is_a<Rational>(other)) {
281  return divrat(down_cast<const Rational &>(other));
282  } else if (is_a<Integer>(other)) {
283  return divrat(down_cast<const Integer &>(other));
284  } else {
285  return other.rdiv(*this);
286  }
287  };
289  virtual RCP<const Number> rdiv(const Number &other) const
290  {
291  if (is_a<Integer>(other)) {
292  return rdivrat(down_cast<const Integer &>(other));
293  } else {
294  throw NotImplementedError("Not Implemented");
295  }
296  };
298  virtual RCP<const Number> pow(const Number &other) const
299  {
300  if (is_a<Integer>(other)) {
301  return powrat(down_cast<const Integer &>(other));
302  } else {
303  return other.rpow(*this);
304  }
305  };
306 
307  virtual RCP<const Number> rpow(const Number &other) const
308  {
309  throw NotImplementedError("Not Implemented");
310  };
311 
312  RCP<const Integer> get_num() const
313  {
314  return integer(SymEngine::get_num(i));
315  }
316 
317  RCP<const Integer> get_den() const
318  {
319  return integer(SymEngine::get_den(i));
320  }
321 };
322 
324 void get_num_den(const Rational &rat, const Ptr<RCP<const Integer>> &num,
325  const Ptr<RCP<const Integer>> &den);
326 
328 inline RCP<const Number> rational(long n, long d)
329 {
330  return Rational::from_two_ints(n, d);
331 }
332 } // namespace SymEngine
333 
334 #endif
#define IMPLEMENT_TYPEID(SYMENGINE_ID)
Inline members and functions.
Definition: basic.h:340
The lowest unit of symbolic representation.
Definition: basic.h:95
Integer Class.
Definition: integer.h:19
virtual bool is_zero() const
Definition: integer.h:53
const integer_class & as_integer_class() const
Convert to integer_class.
Definition: integer.h:48
virtual bool is_negative() const
Definition: integer.h:73
virtual RCP< const Number > mul(const Number &other) const =0
Multiplication.
virtual RCP< const Number > add(const Number &other) const =0
Addition.
Rational Class.
Definition: rational.h:16
virtual RCP< const Number > pow(const Number &other) const
Converts the param other appropriately and then calls powrat
Definition: rational.h:298
RCP< const Basic > rpowrat(const Integer &other) const
Definition: rational.cpp:195
static RCP< const Number > from_mpq(const rational_class &i)
Definition: rational.cpp:23
const rational_class & as_rational_class() const
Convert to rational_class.
Definition: rational.h:50
virtual int compare(const Basic &o) const
Definition: rational.cpp:115
bool is_int() const
Definition: rational.h:70
RCP< const Number > mulrat(const Integer &other) const
Definition: rational.h:144
virtual bool is_complex() const
Definition: rational.h:86
RCP< const Number > addrat(const Rational &other) const
Definition: rational.h:105
rational_class i
i : object of rational_class
Definition: rational.h:19
virtual bool is_one() const
Definition: rational.h:60
RCP< const Number > divrat(const Rational &other) const
Definition: rational.h:151
virtual RCP< const Number > rsub(const Number &other) const
Converts the param other appropriately and then calls rsubrat
Definition: rational.h:258
virtual RCP< const Number > sub(const Number &other) const
Converts the param other appropriately and then calls subrat
Definition: rational.h:247
RCP< const Number > divrat(const Integer &other) const
Definition: rational.h:166
virtual bool __eq__(const Basic &o) const
Definition: rational.cpp:106
virtual RCP< const Number > mul(const Number &other) const
Converts the param other appropriately and then calls mulrat
Definition: rational.h:267
virtual RCP< const Number > rdiv(const Number &other) const
Converts the param other appropriately and then calls rdivrat
Definition: rational.h:289
virtual bool is_positive() const
Definition: rational.h:75
virtual bool is_minus_one() const
Definition: rational.h:65
static RCP< const Number > from_two_ints(const Integer &n, const Integer &d)
Definition: rational.cpp:44
virtual RCP< const Number > add(const Number &other) const
Converts the param other appropriately and then calls addrat
Definition: rational.h:236
RCP< const Number > subrat(const Rational &other) const
Definition: rational.h:119
bool is_canonical(const rational_class &i) const
Definition: rational.cpp:8
virtual RCP< const Number > div(const Number &other) const
Converts the param other appropriately and then calls divrat
Definition: rational.h:278
RCP< const Rational > neg() const
Definition: rational.h:92
virtual bool is_negative() const
Definition: rational.h:80
RCP< const Number > powrat(const Integer &other) const
Definition: rational.h:193
RCP< const Number > subrat(const Integer &other) const
Definition: rational.h:126
virtual hash_t __hash__() const
Definition: rational.cpp:96
RCP< const Number > mulrat(const Rational &other) const
Definition: rational.h:137
RCP< const Number > addrat(const Integer &other) const
Definition: rational.h:112
virtual bool is_zero() const
Definition: rational.h:55
T move(T... args)
Main namespace for SymEngine package.
Definition: add.cpp:19
void get_num_den(const Rational &rat, const Ptr< RCP< const Integer >> &num, const Ptr< RCP< const Integer >> &den)
returns the num and den of rational rat as RCP<const Integer>
Definition: rational.cpp:130
std::enable_if< std::is_integral< T >::value, RCP< const Integer > >::type integer(T i)
Definition: integer.h:200
RCP< const Basic > exp(const RCP< const Basic > &x)
Returns the natural exponential function E**x = pow(E, x)
Definition: pow.cpp:270
RCP< const Number > rational(long n, long d)
convenience creator from two longs
Definition: rational.h:328
STL namespace.