GteBSRational.h
Go to the documentation of this file.
1 // David Eberly, Geometric Tools, Redmond WA 98052
2 // Copyright (c) 1998-2017
3 // Distributed under the Boost Software License, Version 1.0.
4 // http://www.boost.org/LICENSE_1_0.txt
5 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
6 // File Version: 3.0.0 (2016/06/19)
7 
8 #pragma once
9 
11 #include <limits>
12 
13 // See the comments in GteBSNumber.h about the UIntegerType requirements. The
14 // denominator of a BSRational is chosen to be positive, which allows some
15 // simplification of comparisons. Also see the comments about exposing the
16 // GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE conditional define.
17 
18 namespace gte
19 {
20 
21 template <typename UIntegerType>
22 class BSRational
23 {
24 public:
25  // Construction. The default constructor generates the zero BSRational.
26  // The constructors that take only numerators set the denominators to one.
27  BSRational();
28  BSRational(BSRational const& r);
29  BSRational(float numerator);
30  BSRational(double numerator);
31  BSRational(int32_t numerator);
32  BSRational(uint32_t numerator);
33  BSRational(int64_t numerator);
34  BSRational(uint64_t numerator);
35  BSRational(BSNumber<UIntegerType> const& numerator);
36  BSRational(float numerator, float denominator);
37  BSRational(double numerator, double denominator);
38  BSRational(BSNumber<UIntegerType> const& numerator,
39  BSNumber<UIntegerType> const& denominator);
40 
41  // Implicit conversions.
42  operator float() const;
43  operator double() const;
44 
45  // Assignment.
47 
48  // Support for std::move.
51 
52  // Member access.
53  inline int GetSign() const;
54  inline BSNumber<UIntegerType> const& GetNumerator() const;
55  inline BSNumber<UIntegerType> const& GetDenomator() const;
56 
57  // Comparisons.
58  bool operator==(BSRational const& r) const;
59  bool operator!=(BSRational const& r) const;
60  bool operator< (BSRational const& r) const;
61  bool operator<=(BSRational const& r) const;
62  bool operator> (BSRational const& r) const;
63  bool operator>=(BSRational const& r) const;
64 
65  // Unary operations.
66  BSRational operator+() const;
67  BSRational operator-() const;
68 
69  // Arithmetic.
70  BSRational operator+(BSRational const& r) const;
71  BSRational operator-(BSRational const& r) const;
72  BSRational operator*(BSRational const& r) const;
73  BSRational operator/(BSRational const& r) const;
78 
79  // Disk input/output. The fstream objects should be created using
80  // std::ios::binary. The return value is 'true' iff the operation
81  // was successful.
82  bool Write(std::ofstream& output) const;
83  bool Read(std::ifstream& input);
84 
85 private:
86  // Generic conversion code that converts to the correctly
87  // rounded result using round-to-nearest-ties-to-even.
88  template <typename UIntType, typename RealType>
89  RealType Convert() const;
90 
91 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
92 public:
93  // List this first so that it shows up first in the debugger watch window.
94  double mValue;
95 private:
96 #endif
97 
99 
100  friend class UnitTestBSRational;
101 };
102 
103 
104 template <typename UIntegerType>
106  :
107  mNumerator(0),
108  mDenominator(1)
109 {
110 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
111  mValue = (double)*this;
112 #endif
113 }
114 
115 template <typename UIntegerType>
117 {
118  *this = r;
119 }
120 
121 template <typename UIntegerType>
123  :
124  mNumerator(numerator),
125  mDenominator(1.0f)
126 {
127 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
128  mValue = (double)*this;
129 #endif
130 }
131 
132 template <typename UIntegerType>
134  :
135  mNumerator(numerator),
136  mDenominator(1.0)
137 {
138 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
139  mValue = (double)*this;
140 #endif
141 }
142 
143 template <typename UIntegerType>
145  :
146  mNumerator(numerator),
147  mDenominator(1)
148 {
149 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
150  mValue = (double)*this;
151 #endif
152 }
153 
154 template <typename UIntegerType>
156  :
157  mNumerator(numerator),
158  mDenominator(1)
159 {
160 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
161  mValue = (double)*this;
162 #endif
163 }
164 
165 template <typename UIntegerType>
167  :
168  mNumerator(numerator),
169  mDenominator(1)
170 {
171 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
172  mValue = (double)*this;
173 #endif
174 }
175 
176 template <typename UIntegerType>
178  :
179  mNumerator(numerator),
180  mDenominator(1)
181 {
182 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
183  mValue = (double)*this;
184 #endif
185 }
186 
187 template <typename UIntegerType>
189  :
190  mNumerator(numerator),
191  mDenominator(1)
192 {
193 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
194  mValue = (double)*this;
195 #endif
196 }
197 
198 template <typename UIntegerType>
200  :
201  mNumerator(numerator),
202  mDenominator(denominator)
203 {
204  LogAssert(mDenominator.mSign != 0, "Division by zero not allowed.");
205  if (mDenominator.mSign < 0)
206  {
207  mNumerator.mSign = -mNumerator.mSign;
208  mDenominator.mSign = 1;
209  }
210 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
211  mValue = (double)*this;
212 #endif
213 }
214 
215 template <typename UIntegerType>
217  :
218  mNumerator(numerator),
219  mDenominator(denominator)
220 {
221  LogAssert(mDenominator.mSign != 0, "Division by zero not allowed.");
222  if (mDenominator.mSign < 0)
223  {
224  mNumerator.mSign = -mNumerator.mSign;
225  mDenominator.mSign = 1;
226  }
227 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
228  mValue = (double)*this;
229 #endif
230 }
231 
232 template <typename UIntegerType>
235  :
236  mNumerator(numerator),
237  mDenominator(denominator)
238 {
239  LogAssert(mDenominator.mSign != 0, "Division by zero not allowed.");
240  if (mDenominator.mSign < 0)
241  {
242  mNumerator.mSign = -mNumerator.mSign;
243  mDenominator.mSign = 1;
244  }
245 
246  // Set the exponent of the denominator to zero, but you can do so only
247  // by modifying the biased exponent. Adjust the numerator accordingly.
248  // This prevents large growth of the exponents in both numerator and
249  // denominator simultaneously.
250  mNumerator.mBiasedExponent -= mDenominator.GetExponent();
251  mDenominator.mBiasedExponent =
252  -(mDenominator.GetUInteger().GetNumBits() - 1);
253 
254 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
255  mValue = (double)*this;
256 #endif
257 }
258 
259 template <typename UIntegerType>
261 {
262  return Convert<uint32_t, float>();
263 }
264 
265 template <typename UIntegerType>
267 {
268  return Convert<uint64_t, double>();
269 }
270 
271 template <typename UIntegerType>
273  BSRational const& r)
274 {
275  mNumerator = r.mNumerator;
276  mDenominator = r.mDenominator;
277 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
278  mValue = (double)*this;
279 #endif
280  return *this;
281 }
282 
283 template <typename UIntegerType>
285 {
286  *this = std::move(r);
287 }
288 
289 template <typename UIntegerType>
291 {
292  mNumerator = std::move(r.mNumerator);
293  mDenominator = std::move(r.mDenominator);
294 #if defined(GTE_BINARY_SCIENTIFIC_SHOW_DOUBLE)
295  mValue = (double)*this;
296 #endif
297  return *this;
298 }
299 
300 template <typename UIntegerType> inline
302 {
303  return mNumerator.GetSign() * mDenominator.GetSign();
304 }
305 
306 template <typename UIntegerType> inline
308 {
309  return mNumerator;
310 }
311 
312 template <typename UIntegerType> inline
314 {
315  return mDenominator;
316 }
317 
318 template <typename UIntegerType>
320 {
321  // Do inexpensive sign tests first for optimum performance.
322  if (mNumerator.mSign != r.mNumerator.mSign)
323  {
324  return false;
325  }
326  if (mNumerator.mSign == 0)
327  {
328  // The numbers are both zero.
329  return true;
330  }
331 
332  return mNumerator * r.mDenominator == mDenominator * r.mNumerator;
333 }
334 
335 template <typename UIntegerType>
337 {
338  return !operator==(r);
339 }
340 
341 template <typename UIntegerType>
343 {
344  // Do inexpensive sign tests first for optimum performance.
345  if (mNumerator.mSign > 0)
346  {
347  if (r.mNumerator.mSign <= 0)
348  {
349  return false;
350  }
351  }
352  else if (mNumerator.mSign == 0)
353  {
354  return r.mNumerator.mSign > 0;
355  }
356  else if (mNumerator.mSign < 0)
357  {
358  if (r.mNumerator.mSign >= 0)
359  {
360  return true;
361  }
362  }
363 
364  return mNumerator * r.mDenominator < mDenominator * r.mNumerator;
365 }
366 
367 template <typename UIntegerType>
369 {
370  return !operator>(r);
371 }
372 
373 template <typename UIntegerType>
375 {
376  return r.operator<(*this);
377 }
378 
379 template <typename UIntegerType>
381 {
382  return !operator<(r);
383 }
384 
385 template <typename UIntegerType>
387 {
388  return *this;
389 }
390 
391 template <typename UIntegerType>
393 {
395 }
396 
397 template <typename UIntegerType>
399  BSRational const& r) const
400 {
401  BSNumber<UIntegerType> product0 = mNumerator * r.mDenominator;
402  BSNumber<UIntegerType> product1 = mDenominator * r.mNumerator;
403  BSNumber<UIntegerType> numerator = product0 + product1;
404 
405  // Complex expressions can lead to 0/denom, where denom is not 1.
406  if (numerator.mSign != 0)
407  {
409  return BSRational(numerator, denominator);
410  }
411  else
412  {
413  return BSRational(0);
414  }
415 }
416 
417 template <typename UIntegerType>
419  BSRational const& r) const
420 {
421  BSNumber<UIntegerType> product0 = mNumerator * r.mDenominator;
422  BSNumber<UIntegerType> product1 = mDenominator * r.mNumerator;
423  BSNumber<UIntegerType> numerator = product0 - product1;
424 
425  // Complex expressions can lead to 0/denom, where denom is not 1.
426  if (numerator.mSign != 0)
427  {
429  return BSRational(numerator, denominator);
430  }
431  else
432  {
433  return BSRational(0);
434  }
435 }
436 
437 template <typename UIntegerType>
439  BSRational const& r) const
440 {
442 
443  // Complex expressions can lead to 0/denom, where denom is not 1.
444  if (numerator.mSign != 0)
445  {
447  return BSRational(numerator, denominator);
448  }
449  else
450  {
451  return BSRational(0);
452  }
453 }
454 
455 template <typename UIntegerType>
457  BSRational const& r) const
458 {
459  LogAssert(r.mNumerator.mSign != 0, "Division by zero not allowed.");
460 
461  BSNumber<UIntegerType> numerator = mNumerator * r.mDenominator;
462 
463  // Complex expressions can lead to 0/denom, where denom is not 1.
464  if (numerator.mSign != 0)
465  {
467  if (denominator.mSign < 0)
468  {
469  numerator.mSign = -numerator.mSign;
470  denominator.mSign = 1;
471  }
472  return BSRational(numerator, denominator);
473  }
474  else
475  {
476  return BSRational(0);
477  }
478 }
479 
480 template <typename UIntegerType>
482  BSRational const& r)
483 {
484  *this = operator+(r);
485  return *this;
486 }
487 
488 template <typename UIntegerType>
490  BSRational const& r)
491 {
492  *this = operator-(r);
493  return *this;
494 }
495 
496 template <typename UIntegerType>
498  BSRational const& r)
499 {
500  *this = operator*(r);
501  return *this;
502 }
503 
504 template <typename UIntegerType>
506  BSRational const& r)
507 {
508  *this = operator/(r);
509  return *this;
510 }
511 
512 template <typename UIntegerType>
513 bool BSRational<UIntegerType>::Write(std::ofstream& output) const
514 {
515  return mNumerator.Write(output) && mDenominator.Write(output);
516 }
517 
518 template <typename UIntegerType>
520 {
521  return mNumerator.Read(input) && mDenominator.Read(input);
522 }
523 
524 template <typename UIntegerType>
525 template <typename UIntType, typename RealType>
527 {
528  if (mNumerator.mSign == 0)
529  {
530  return (RealType)0;
531  }
532 
533  // The ratio is abstractly of the form (1.u*2^p)/(1.v*2^q). Convert to
534  // the form (1.u/1.v)*2^{p-q}, if 1.u >= 1.v, or to the form
535  // (2*(1.u)/1.v)*2*{p-q-1}) if 1.u < 1.v. The final form n/d must be in
536  // the interval [1,2).
538  int32_t sign = n.mSign * d.mSign;
539  n.mSign = 1;
540  d.mSign = 1;
541  int32_t pmq = n.GetExponent() - d.GetExponent();
542  n.mBiasedExponent = 1 - n.GetUInteger().GetNumBits();
543  d.mBiasedExponent = 1 - d.GetUInteger().GetNumBits();
545  {
546  ++n.mBiasedExponent;
547  --pmq;
548  }
549 
550  // At this time, n/d = 1.c in [1,2). Define the sequence of bits
551  // w = 1c = w_{imax} w_{imax-1} ... w_0 w_{-1} w_{-2} ... where
552  // imax = precision(RealType)-1 and w_{imax} = 1.
553 
554  // Compute 'precision' bits for w, the leading bit guaranteed to be 1
555  // and occurring at index (1 << (precision-1)).
556  BSNumber<UIntegerType> one(1), two(2);
557  int const imax = std::numeric_limits<RealType>::digits - 1;
558  UIntType w = 0;
559  UIntType mask = ((UIntType)1 << imax);
560  for (int i = imax; i >= 0; --i, mask >>= 1)
561  {
563  {
564  n = two * n;
565  }
566  else
567  {
568  n = two * (n - d);
569  w |= mask;
570  }
571  }
572 
573  // Apply the mode round-to-nearest-ties-to-even to decide whether to
574  // round down or up. We computed w = w_{imax} ... w_0. The remainder
575  // is n/d = w_{imax+1}.w_{imax+2}... in [0,2). Compute n'/d = (n-d)/d
576  // in [-1,1). Round-to-nearest-ties-to-even mode is the following,
577  // where we need only test the sign of n'. A remainder of "half" is
578  // the case n' = 0.
579  // Round down when n' < 0 or (n' = 0 and w_0 = 0): use w
580  // Round up when n' > 0 or (n' = 0 and w_0 == 1): use w+1
581  n = n - d;
582  if (n.mSign > 0 || (n.mSign == 0 && (w & 1) == 1))
583  {
584  ++w;
585  }
586 
587  if (w > 0)
588  {
589  // Ensure that the low-order bit of w is 1 (required for BSNumber
590  // integer part).
591  int32_t trailing = GetTrailingBit(w);
592  w >>= trailing;
593  pmq += trailing;
594 
595  // Compute a BSNumber with integer part w and the appropriate
596  // number of bits and exponents.
598  result.mBiasedExponent = pmq - imax;
599  RealType converted = (RealType)result;
600  if (sign < 0)
601  {
602  converted = -converted;
603  }
604  return converted;
605  }
606  else
607  {
608  return (RealType)0;
609  }
610 }
611 
612 
613 }
614 
615 namespace std
616 {
617  template <typename UIntegerType> inline
619  gte::BSRational<UIntegerType> const& number)
620  {
621  return (number.GetSign() >= 0 ? number : -number);
622  }
623 }
GLdouble n
Definition: glcorearb.h:2003
BSRational & operator-=(BSRational const &r)
GTE_IMPEXP int32_t GetTrailingBit(uint32_t value)
UIntegerType const & GetUInteger() const
Definition: GteBSNumber.h:364
BSNumber< UIntegerType > mNumerator
Definition: GteBSRational.h:98
#define LogAssert(condition, message)
Definition: GteLogger.h:86
bool Write(std::ofstream &output) const
bool operator==(BSRational const &r) const
int GetSign() const
GLint GLuint mask
Definition: glcorearb.h:119
int32_t GetExponent() const
Definition: GteBSNumber.h:358
GLubyte GLubyte GLubyte GLubyte w
Definition: glcorearb.h:852
friend class UnitTestBSRational
INT32 * numerator
Definition: wglext.h:821
BSRational operator-() const
BSRational & operator+=(BSRational const &r)
BSNumber< UIntegerType > mDenominator
Definition: GteBSRational.h:98
BSRational operator*(BSRational const &r) const
gte::BSRational< UIntegerType > abs(gte::BSRational< UIntegerType > const &number)
bool operator<=(BSRational const &r) const
int32_t mSign
Definition: GteBSNumber.h:160
INT32 INT32 * denominator
Definition: wglext.h:821
BSNumber< UIntegerType > const & GetNumerator() const
GLboolean r
Definition: glcorearb.h:1217
GLenum GLenum GLenum input
Definition: glext.h:9913
bool operator>=(BSRational const &r) const
GLfloat f
Definition: glcorearb.h:1921
BSRational & operator*=(BSRational const &r)
bool Read(std::ifstream &input)
BSRational & operator/=(BSRational const &r)
BSRational operator+() const
bool operator>(BSRational const &r) const
BSRational & operator=(BSRational const &r)
RealType Convert() const
BSNumber< UIntegerType > const & GetDenomator() const
GLuint64EXT * result
Definition: glext.h:10003
bool operator<(BSRational const &r) const
BSRational operator/(BSRational const &r) const
int32_t mBiasedExponent
Definition: GteBSNumber.h:161
bool operator!=(BSRational const &r) const


geometric_tools_engine
Author(s): Yijiang Huang
autogenerated on Thu Jul 18 2019 03:59:59