vnl_rational.cxx
Go to the documentation of this file.
1 // This is core/vnl/vnl_rational.cxx
2 #include <cassert>
3 #include "vnl_rational.h"
4 //:
5 // \file
6 
7 #include <vnl/vnl_numeric_traits.h> // for vnl_numeric_traits<long>::maxval
8 
9 template<typename FloatingType>
10 inline void makeNumDen( FloatingType d, long &num_, long &den_)
11 {
12  bool sign = d<0;
13  if (sign) d = -d;
14 
15  // Continued fraction approximation of abs(d): recursively determined
16  long den=0L, num=1L, prev_den=1L, prev_num=0L;
17 
18  while (d*num < 1e9 && d*den < 1e9) {
19  long a = (long)d; // integral part of d
20  d -= a; // certainly >= 0
21  long temp = num; num = a*num + prev_num; prev_num = temp;
22  temp = den; den = a*den + prev_den; prev_den = temp;
23  if (d < 1e-6) break;
24  d = 1/d;
25  }
26  num_ = num; den_ = den;
27  if (sign) num_ = -num_;
28  // no need to normalize() since prev_num and prev_den have guaranteed a gcd=1
29 }
30 
31 //: Creates a rational from a double.
32 // This is done by computing the continued fraction approximation for d.
34 {
35  makeNumDen<double>(d,num_,den_);
36 }
37 
38 //: Creates a rational from a double.
39 // This is done by computing the continued fraction approximation for d.
41 {
42  makeNumDen<double>(f,num_,den_);
43 }
44 
45 //: Multiply/assign: replace lhs by lhs * rhs
46 // Note that 0 * Inf and Inf * 0 are undefined.
47 // Also note that there could be integer overflow during this calculation!
48 // In that case, an approximate result will be returned.
50 {
51  assert(num_!=0 || den_ != 0); // 0 * Inf is undefined
52  long a = vnl_rational::gcd(r.numerator(),den_),
54  num_ /= b; den_ /= a;
55  a = r.numerator()/a; b = r.denominator()/b;
56  // find out whether overflow would occur; in that case, return approximate result
57  double n = double(a) * double(num_),
58  d = double(b) * double(den_);
60  { num_ *= a; den_ *= b; normalize(); return *this; }
61  else
62  return *this = vnl_rational(n/d);
63 }
64 
65 //: Multiply/assign: replace lhs by lhs * rhs
66 // Note that there could be integer overflow during this calculation!
67 // In that case, an approximate result will be returned.
69 {
70  long a = vnl_rational::gcd(r,den_);
71  den_ /= a; r /= a;
72  // find out whether overflow would occur; in that case, return approximate result
73  double n = double(r) * double(num_);
75  { num_ *= r; normalize(); return *this; }
76  else
77  return *this = vnl_rational(n/double(den_));
78 }
79 
80 //: Divide/assign: replace lhs by lhs / rhs
81 // Note that 0 / 0 and Inf / Inf are undefined.
82 // Also note that there could be integer overflow during this calculation!
83 // In that case, an approximate result will be returned.
85 {
86  assert(num_!=0 || den_ != 0); // 0/0, Inf/Inf undefined
87  long a = vnl_rational::gcd(r.numerator(),num_),
89  num_ /= a; den_ /= b;
90  a = r.numerator()/a; b = r.denominator()/b;
91  // find out whether overflow would occur; in that case, return approximate result
92  double n = double(b) * double(num_),
93  d = double(a) * double(den_);
95  { num_ *= b; den_ *= a; normalize(); return *this; }
96  else
97  return *this = vnl_rational(n/d);
98 }
99 
100 //: Divide/assign: replace lhs by lhs / rhs
101 // Note that 0 / 0 is undefined.
102 // Also note that there could be integer overflow during this calculation!
103 // In that case, an approximate result will be returned.
105 {
106  assert(num_!=0 || r != 0); // 0/0 undefined
107  long a = vnl_rational::gcd(r,num_);
108  num_ /= a; r /= a;
109  // find out whether overflow would occur; in that case, return approximate result
110  double d = double(r) * double(den_);
112  { den_ *= r; normalize(); return *this; }
113  else
114  return *this = vnl_rational(double(num_)/d);
115 }
long num_
Numerator portion.
Definition: vnl_rational.h:76
static long gcd(long l1, long l2)
Calculate greatest common divisor of two integers.
Definition: vnl_rational.h:283
vnl_rational & operator *=(vnl_rational const &r)
Multiply/assign: replace lhs by lhs * rhs.
Templated zero/one/precision.
vnl_rational & operator/=(vnl_rational const &r)
Divide/assign: replace lhs by lhs / rhs.
void makeNumDen(FloatingType d, long &num_, long &den_)
long numerator() const
Return the numerator of the (simplified) rational number representation.
Definition: vnl_rational.h:133
long den_
Denominator portion.
Definition: vnl_rational.h:77
long denominator() const
Return the denominator of the (simplified) rational number representation.
Definition: vnl_rational.h:135
void normalize()
Private function to normalize numerator/denominator of rational number.
Definition: vnl_rational.h:292
High-precision rational numbers.
vnl_rational()
Creates a rational with given numerator and denominator.
Definition: vnl_rational.h:86
High-precision rational numbers.
Definition: vnl_rational.h:73