1 /*
2   This code is based on code from the Geometric Tools library,
3   which is licensed under a boost license.
4   Such usage is permitted by the boost license; for details,
5   please see the boost license below.
6 */
7 
8 // Geometric Tools, LLC
9 // Copyright (c) 1998-2014
10 // Distributed under the Boost Software License, Version 1.0.
11 // http://www.boost.org/LICENSE_1_0.txt
12 // http://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
13 
14 /*************************************************************************
15  *                                                                       *
16  * We release our improvements to the wildMagic code under our standard  *
17  * Vega FEM license, as follows:                                         *
18  *                                                                       *
19  * Vega FEM Simulation Library Version 3.1                               *
20  *                                                                       *
21  * "improvements to the wildMagic library" , Copyright (C) 2016 USC      *
22  * All rights reserved.                                                  *
23  *                                                                       *
24  * Code author: Yijing Li                                                *
25  * http://www.jernejbarbic.com/code                                      *
26  *                                                                       *
27  * Funding: National Science Foundation                                  *
28  *                                                                       *
29  * This library is free software; you can redistribute it and/or         *
30  * modify it under the terms of the BSD-style license that is            *
31  * included with this library in the file LICENSE.txt                    *
32  *                                                                       *
33  * This library is distributed in the hope that it will be useful,       *
34  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
35  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file     *
36  * LICENSE.TXT for more details.                                         *
37  *                                                                       *
38  *************************************************************************/
39 
40 
41 #ifndef RATIONAL_H
42 #define RATIONAL_H
43 
44 
45 #include "integer.h"
46 #include <stdint.h>
47 
48 class RationalException : public std::exception
49 {
50 public:
51   RationalException(const char * reason);
52   RationalException(const std::string & reason);
53   virtual ~RationalException() throw();
54   virtual const char * what() const throw();
55 
56 protected:
57   std::string r;
58 };
59 
60 // N is the number of 32-bit words per Integer numerator/denominator
61 template <int N>
62 class Rational
63 {
64 public:
65 
66   // Construction.
67   Rational ();  // default rational is 0/1
68   Rational (const Rational & rat);
69   Rational (const Integer<N> & numer);
70   Rational (const Integer<N> & numer, const Integer<N>& denom);
71 
72   // Construction converters.
73   Rational (int numer);
74   Rational (int numer, int denom);
75   Rational (float value);
76   Rational (double value);
77 
78   // Member access.
Numer()79   inline Integer<N> & Numer () { return mNumer; }
Denom()80   inline Integer<N> & Denom () { return mDenom; }
Numer()81   inline const Integer<N> & Numer () const { return mNumer; }
Denom()82   inline const Integer<N> & Denom () const { return mDenom; }
83 
84   // Assignment.
85   Rational & operator= (const Rational & rat);
86 
87   // Comparison.
88   bool operator== (const Rational & rat) const;
89   bool operator!= (const Rational & rat) const;
90   bool operator<= (const Rational & rat) const;
91   bool operator<  (const Rational & rat) const;
92   bool operator>= (const Rational & rat) const;
93   bool operator>  (const Rational & rat) const;
94 
95   // Arithmetic operations.
96   Rational operator+ (const Rational & rat) const;
97   Rational operator- (const Rational & rat) const;
98   Rational operator* (const Rational & rat) const;
99   Rational operator/ (const Rational & rat) const;
100   Rational operator- () const;
101 
102   // Arithmetic updates.
103   Rational & operator+= (const Rational & rat);
104   Rational & operator-= (const Rational & rat);
105   Rational & operator*= (const Rational & rat);
106   Rational & operator/= (const Rational & rat);
107 
108   // Conversions to float and double.
109   void convertTo (float& value) const;
110   void convertTo (double& value) const;
111   double toDouble() const;
112 
113   // Compute the absolute value of the rational number.
114   Rational abs () const;
115 
116 private:
117 	typedef RationalException Exception;
118   // Cancel any powers of two common to the numerator and
119   // denominator.
120   void EliminatePowersOfTwo ();
121 
122   Integer<N> mNumer, mDenom;
123 };
124 
125 template <int N>
126 Rational<N> operator+ (const Integer<N>& ival, const Rational<N>& rat);
127 
128 template <int N>
129 Rational<N> operator- (const Integer<N>& ival, const Rational<N>& rat);
130 
131 template <int N>
132 Rational<N> operator* (const Integer<N>& ival, const Rational<N>& rat);
133 
134 template <int N>
135 Rational<N> operator/ (const Integer<N>& ival, const Rational<N>& rat);
136 
137 
138 
Rational()139 template <int N> Rational<N>::Rational () : mNumer(0), mDenom(1) {}
140 
Rational(const Rational & rat)141 template <int N> Rational<N>::Rational (const Rational & rat) : mNumer(rat.mNumer), mDenom(rat.mDenom) {}
142 
Rational(const Integer<N> & numer)143 template <int N> Rational<N>::Rational (const Integer<N>& numer) : mNumer(numer), mDenom(1) {}
144 
Rational(const Integer<N> & numer,const Integer<N> & denom)145 template <int N> Rational<N>::Rational (const Integer<N>& numer, const Integer<N>& denom) : mNumer(numer), mDenom(denom) {}
146 
Rational(int numer)147 template <int N> Rational<N>::Rational (int numer) : mNumer(numer), mDenom(1) {}
148 
Rational(int numer,int denom)149 template <int N> Rational<N>::Rational (int numer, int denom) : mNumer(numer), mDenom(denom) {}
150 
151 template <int N> Rational<N>& Rational<N>::operator= (const Rational & rat)
152 {
153   if (this != &rat)
154   {
155     mNumer = rat.mNumer;
156     mDenom = rat.mDenom;
157   }
158   return *this;
159 }
160 
161 template <int N> bool Rational<N>::operator== (const Rational & rat) const
162 {
163   return mNumer*rat.mDenom == mDenom*rat.mNumer;
164 }
165 
166 template <int N> bool Rational<N>::operator!= (const Rational & rat) const
167 {
168   return mNumer*rat.mDenom != mDenom*rat.mNumer;
169 }
170 
171 template <int N> bool Rational<N>::operator<= (const Rational & rat) const
172 {
173   Integer<N> prod0 = mNumer*rat.mDenom;
174   Integer<N> prod1 = mDenom*rat.mNumer;
175   if (mDenom > 0)
176     return (rat.mDenom > 0 ? prod0 <= prod1 : prod0 >= prod1);
177   else
178     return (rat.mDenom > 0 ? prod0 >= prod1 : prod0 <= prod1);
179 }
180 
181 template <int N> bool Rational<N>::operator< (const Rational & rat) const
182 {
183   Integer<N> prod0 = mNumer*rat.mDenom;
184   Integer<N> prod1 = mDenom*rat.mNumer;
185   if (mDenom > 0)
186     return (rat.mDenom > 0 ? prod0 < prod1 : prod0 > prod1);
187   else
188     return (rat.mDenom > 0 ? prod0 > prod1 : prod0 < prod1);
189 }
190 
191 template <int N> bool Rational<N>::operator>= (const Rational & rat) const
192 {
193   Integer<N> prod0 = mNumer*rat.mDenom;
194   Integer<N> prod1 = mDenom*rat.mNumer;
195   if (mDenom > 0)
196     return (rat.mDenom > 0 ? prod0 >= prod1 : prod0 <= prod1);
197   else
198     return (rat.mDenom > 0 ? prod0 <= prod1 : prod0 >= prod1);
199 }
200 
201 template <int N> bool Rational<N>::operator> (const Rational & rat) const
202 {
203   Integer<N> prod0 = mNumer*rat.mDenom;
204   Integer<N> prod1 = mDenom*rat.mNumer;
205   if (mDenom > 0)
206     return (rat.mDenom > 0 ? prod0 > prod1 : prod0 < prod1);
207   else
208     return (rat.mDenom > 0 ? prod0 < prod1 : prod0 > prod1);
209 }
210 
211 template <int N> Rational<N> Rational<N>::operator+ (const Rational & rat) const
212 {
213   Rational sum;
214   sum.mNumer = mNumer*rat.mDenom + mDenom*rat.mNumer;
215   sum.mDenom = mDenom*rat.mDenom;
216   sum.EliminatePowersOfTwo();
217   return sum;
218 }
219 
220 template <int N> Rational<N> Rational<N>::operator- (const Rational & rat) const
221 {
222   Rational diff;
223   diff.mNumer = mNumer*rat.mDenom - mDenom*rat.mNumer;
224   diff.mDenom = mDenom*rat.mDenom;
225   diff.EliminatePowersOfTwo();
226   return diff;
227 }
228 
229 template <int N> Rational<N> Rational<N>::operator* (const Rational & rat) const
230 {
231   Rational prod;
232   prod.mNumer = mNumer*rat.mNumer;
233   prod.mDenom = mDenom*rat.mDenom;
234   prod.EliminatePowersOfTwo();
235   return prod;
236 }
237 
238 template <int N> Rational<N> Rational<N>::operator/ (const Rational & rat) const
239 {
240   Rational quot;
241   quot.mNumer = mNumer*rat.mDenom;
242   quot.mDenom = mDenom*rat.mNumer;
243   quot.EliminatePowersOfTwo();
244   return quot;
245 }
246 
247 template <int N> Rational<N> Rational<N>::operator- () const
248 {
249   Rational neg;
250   neg.mNumer = -mNumer;
251   neg.mDenom = mDenom;
252   return neg;
253 }
254 
255 template <int N> Rational<N> operator+ (const Integer<N>& ival, const Rational<N>& rat)
256 {
257   Rational<N> sum;
258   sum.Numer() = ival*rat.Denom() + rat.Numer();
259   sum.Denom() = rat.Denom();
260   return sum;
261 }
262 
263 template <int N> Rational<N> operator- (const Integer<N>& ival, const Rational<N>& rat)
264 {
265   Rational<N> diff;
266   diff.Numer() = ival*rat.Denom() - rat.Numer();
267   diff.Denom() = rat.Denom();
268   return diff;
269 }
270 //----------------------------------------------------------------------------
271 template <int N>
272 Rational<N> operator* (const Integer<N>& ival, const Rational<N>& rat)
273 {
274   Rational<N> prod;
275   prod.Numer() = ival*rat.Numer();
276   prod.Denom() = rat.Denom();
277   return prod;
278 }
279 //----------------------------------------------------------------------------
280 template <int N>
281 Rational<N> operator/ (const Integer<N>& ival, const Rational<N>& rat)
282 {
283   Rational<N> quot;
284   quot.Numer() = rat.Denom()*ival;
285   quot.Denom() = rat.Numer();
286   return quot;
287 }
288 //----------------------------------------------------------------------------
289 template <int N>
290 Rational<N>& Rational<N>::operator+= (const Rational & rat)
291 {
292   *this = *this + rat;
293   EliminatePowersOfTwo();
294   return *this;
295 }
296 //----------------------------------------------------------------------------
297 template <int N>
298 Rational<N>& Rational<N>::operator-= (const Rational & rat)
299 {
300   *this = *this - rat;
301   EliminatePowersOfTwo();
302   return *this;
303 }
304 //----------------------------------------------------------------------------
305 template <int N>
306 Rational<N>& Rational<N>::operator*= (const Rational & rat)
307 {
308   *this = (*this)*rat;
309   EliminatePowersOfTwo();
310   return *this;
311 }
312 //----------------------------------------------------------------------------
313 template <int N>
314 Rational<N>& Rational<N>::operator/= (const Rational & rat)
315 {
316   *this = (*this)/rat;
317   EliminatePowersOfTwo();
318   return *this;
319 }
320 //----------------------------------------------------------------------------
321 template <int N>
abs()322 Rational<N> Rational<N>::abs () const
323 {
324   return (*this >= 0 ? *this : -(*this));
325 }
326 //----------------------------------------------------------------------------
327 template <int N>
EliminatePowersOfTwo()328 void Rational<N>::EliminatePowersOfTwo ()
329 {
330   if ((mNumer.buffer[0] & 1) > 0
331       ||  (mDenom.buffer[0] & 1) > 0)
332   {
333     // Neither term is divisible by 2 (quick out).
334     return;
335   }
336 
337   int block0 = mNumer.getTrailingBlock();
338   if (block0 == -1)
339   {
340     // Numerator is zero.
341     mDenom = 1;
342     return;
343   }
344 
345   int block1 = mDenom.getTrailingBlock();
346   if (block1 < 0)
347     throw Exception("Denominator should never be zero in Rational<N>::EliminatePowersOfTwo");
348 
349   int minBlock = (block0 < block1 ? block0 : block1);
350   int bit0 = mNumer.getTrailingBit(block0);
351   int bit1 = mDenom.getTrailingBit(block1);
352   int minBit = (bit0 < bit1 ? bit0 : bit1);
353   int shift = 16*minBlock + minBit;
354   mNumer >>= shift;
355   mDenom >>= shift;
356 }
357 //----------------------------------------------------------------------------
358 
359 //----------------------------------------------------------------------------
360 // Conversions between rational numbers and 'float'.
361 //----------------------------------------------------------------------------
362 template <int N>
Rational(float value)363 Rational<N>::Rational (float value)
364 {
365   mDenom = Integer<N>(1);
366   if (value == 0.0f)
367   {
368     // Exponent is zero, mantissa is zero, number is +0 (sign bit = 0)
369     // or -0 (sign bit = 1).  Return rational value for +0.
370     mNumer = Integer<N>(0);
371     return;
372   }
373 
374   unsigned int bits = *(unsigned int*)&value;
375   unsigned int sign = (0x80000000 & bits);
376   int exponent = ((0x7F800000 & bits) >> 23);
377   int mantissa = (0x007FFFFF & bits);
378 
379   if (1 <= exponent && exponent <= 254)
380   {
381     // The number is normal:  (-1)^s * 2^{e-127} * 1.m
382     mNumer = Integer<N>((1 << 23) + mantissa);
383     int power = exponent - 150;
384     if (power > 0)
385     {
386       mNumer <<= power;
387     }
388     else if (power < 0)
389     {
390       mDenom <<= -power;
391     }
392   }
393   else if (exponent == 0)
394   {
395     // The number is subnormal (denormal):  (-1)^s * 2^{-126} * 0.m
396     mNumer = Integer<N>(mantissa);
397     mDenom <<= 149;
398   }
399   else  // exponent == 255
400   {
401   #ifdef WM5_ASSERT_ON_RATIONAL_CONVERT_NAN
402     if (mantissa > 0)
403     {
404       if (mantissa & 0x00400000)
405       {
406         assertion(false, "Input is quiet NaN.\n");
407       }
408       else
409       {
410         // Payload is (mantissa & 0x003FFFFF).
411         assertion(false, "Input is signaling NaN.\n");
412       }
413     }
414     else
415     {
416       assertion(false, "Input is an infinity.\n");
417     }
418   #endif
419     // The number is infinite, a quiet NaN, or a signaling NaN.  In all
420     // cases, represent them as max_normal_float.
421     mNumer = Integer<N>((1 << 24) - 1);
422     mNumer <<= 104;
423   }
424 
425   if (sign)
426   {
427     mNumer = -mNumer;
428   }
429 }
430 //----------------------------------------------------------------------------
431 template <int N>
convertTo(float & value)432 void Rational<N>::convertTo (float& value) const
433 {
434   if (mNumer == 0)
435   {
436     value = 0.0f;
437     return;
438   }
439 
440   // Compute the sign of the result and the absolute values of the numerator
441   // and denominator.
442   int sign0 = mNumer.getSign();
443   int sign1 = mDenom.getSign();
444   int sign = sign0*sign1;
445   Integer<N> absNumer = sign0*mNumer;
446   Integer<N> absDenom = sign1*mDenom;
447 
448   // Get the leading bits of of the numerator and denominator.
449   int nbit = absNumer.getLeadingBit();
450   int dbit = absDenom.getLeadingBit();
451 
452   // The rational is for the form N/D = 2^{nbit-dbit}*(1+n)/(1+d), where
453   // n and d are in [0,1).  Convert to N'/D' = (1+n)/(1+d).
454   int power = nbit - dbit;
455   if (power > 0)
456   {
457     absDenom <<= power;
458   }
459   else if (power < 0)
460   {
461     absNumer <<= -power;
462   }
463 
464   // To represent (1+n)/(1+d) = 1+m, where m in [0,1), we need n >= d.  If
465   // n < d, convert to N"/D" = (2*(1+n))/(1+d) = 1+m, which is in [0,1).
466   if (absNumer < absDenom)
467   {
468     absNumer <<= 1;
469     --power;
470   }
471 
472   int result;
473   if (power <= 127)
474   {
475     if (power >= -149)
476     {
477       int exponent, bit, shift;
478       if (power >= -126)
479       {
480         // normal_float, 1.c * 2^{e - 127}
481         exponent = power + 127;
482         bit = 1;
483         shift = 0;
484       }
485       else
486       {
487         // subnormal_float, 0.c * 2^{-126}
488         exponent = 0;
489         bit = 0;
490         absDenom <<= 1;
491         shift = -(power + 127);
492       }
493 
494       int mantissa = 0;
495       Integer<N> one(1);
496       for(int mask = ((1 << 22) >> shift); mask > 0; mask >>= 1)
497       {
498         if (bit == 1)
499         {
500           absNumer -= absDenom;
501         }
502         absNumer <<= 1;
503 
504         if (absNumer >= absDenom)
505         {
506           bit = 1;
507           mantissa |= mask;
508         }
509         else
510         {
511           bit = 0;
512         }
513       }
514 
515       result = (exponent << 23) | mantissa;
516     }
517     else
518     {
519       // Smaller than min_subnormal_float, truncate to zero.
520       result = 0;
521     }
522   }
523   else
524   {
525     // Larger than max_normal_float, truncate to this value.
526     result = 0x7F7FFFFF;
527   }
528 
529   if (sign < 0)
530   {
531     result |= 0x80000000;
532   }
533   value = *(float*)&result;
534 }
535 //----------------------------------------------------------------------------
536 
537 //----------------------------------------------------------------------------
538 // Conversions between rational numbers and 'double'.
539 //----------------------------------------------------------------------------
540 template <int N>
Rational(double value)541 Rational<N>::Rational (double value)
542 {
543   mDenom = Integer<N>(1);
544   if (value == 0.0)
545   {
546     // Exponent is zero, mantissa is zero, number is +0 (sign bit = 0)
547     // or -0 (sign bit = 1).  Return rational value for +0.
548     mNumer = Integer<N>(0);
549     return;
550   }
551 
552   uint64_t bits = *(uint64_t*)&value;
553   uint64_t sign = (0x8000000000000000ULL & bits);
554   int exponent = (int)((0x7FFF000000000000LL & bits) >> 52);
555   int64_t mantissa = (0x000FFFFFFFFFFFFFLL & bits);
556   int mlo24 = (int)(mantissa & 0x0000000000FFFFFFLL);
557   int mhi28 = (int)((mantissa & 0x000FFFFFFF000000LL) >> 24);
558 
559   if (1 <= exponent && exponent <= 2046)
560   {
561     // The number is normal:  (-1)^s * 2^{e-1023} * 1.m
562     Integer<N> numer0(1);
563     numer0 <<= 52;  // = (1 << 52);
564     Integer<N> numer1(mhi28);
565     numer1 <<= 24;
566     numer1 += Integer<N>(mlo24);
567     mNumer = numer0 + numer1;  // (1LL < 52) + mantissa
568     int power = exponent - 1075;
569     if (power > 0)
570     {
571       mNumer <<= power;
572     }
573     else if (power < 0)
574     {
575       mDenom <<= -power;
576     }
577   }
578   else if (exponent == 0)
579   {
580     // The number is subnormal (denormal):  (-1)^s * 2^{-1022} * 0.m
581     mNumer = Integer<N>(mhi28);
582     mNumer <<= 24;
583     mNumer += Integer<N>(mlo24);  // mantissa
584     mDenom <<= 1074;
585   }
586   else  // exponent == 1023
587   {
588   #ifdef WM5_ASSERT_ON_RATIONAL_CONVERT_NAN
589     if (mantissa > 0)
590     {
591       if (mantissa & 0x0008000000000000LL)
592       {
593         assertion(false, "Input is quiet NaN.\n");
594       }
595       else
596       {
597         // Payload is (mantissa & 0x0007FFFFFFFFFFFFLL).
598         assertion(false, "Input is signaling NaN.\n");
599       }
600     }
601     else
602     {
603       assertion(false, "Input is an infinity.\n");
604     }
605   #endif
606     // The number is infinite, a quiet NaN, or a signaling NaN.  In all
607     // cases, represent them as max_normal_double.
608     mNumer = Integer<N>(1);
609     mNumer <<= 53;
610     mNumer -= Integer<N>(1);  // (1LL << 53) - 1L
611     mNumer <<= 971;
612   }
613 
614   if (sign)
615   {
616     mNumer = -mNumer;
617   }
618 }
619 //----------------------------------------------------------------------------
620 template <int N>
convertTo(double & value)621 void Rational<N>::convertTo (double& value) const
622 {
623   if (mNumer == 0)
624   {
625     value = 0.0;
626     return;
627   }
628 
629   // Compute the sign of the result and the absolute values of the numerator
630   // and denominator.
631   int sign0 = mNumer.getSign();
632   int sign1 = mDenom.getSign();
633   int sign = sign0*sign1;
634   Integer<N> absNumer = sign0*mNumer;
635   Integer<N> absDenom = sign1*mDenom;
636 
637   // Get the leading bits of of the numerator and denominator.
638   int nbit = absNumer.getLeadingBit();
639   int dbit = absDenom.getLeadingBit();
640 
641   // The rational is for the form N/D = 2^{nbit-dbit}*(1+n)/(1+d), where
642   // n and d are in [0,1).  Convert to N'/D' = (1+n)/(1+d).
643   int power = nbit - dbit;
644   if (power > 0)
645   {
646     absDenom <<= power;
647   }
648   else if (power < 0)
649   {
650     absNumer <<= -power;
651   }
652 
653   // To represent (1+n)/(1+d) = 1+m, where m in [0,1), we need n >= d.  If
654   // n < d, convert to N"/D" = (2*(1+n))/(1+d) = 1+m, which is in [0,1).
655   if (absNumer < absDenom)
656   {
657     absNumer <<= 1;
658     --power;
659   }
660 
661   int64_t result;
662   if (power <= 1023)
663   {
664     if (power >= -1074)
665     {
666       int64_t exponent;
667       int bit, shift;
668       if (power >= -1022)
669       {
670         // normal_float, 1.c * 2^{e - 1023}
671         exponent = power + 1023;
672         bit = 1;
673         shift = 0;
674       }
675       else
676       {
677         // subnormal_float, 0.c * 2^{-1022}
678         exponent = 0;
679         bit = 0;
680         absDenom <<= 1;
681         shift = -(power + 1023);
682       }
683 
684       int64_t mantissa = 0;
685       Integer<N> one(1);
686       for(int64_t mask = ((1LL << 51) >> shift); mask > 0; mask >>= 1)
687       {
688         if (bit == 1)
689         {
690           absNumer -= absDenom;
691         }
692         absNumer <<= 1;
693 
694         if (absNumer >= absDenom)
695         {
696           bit = 1;
697           mantissa |= mask;
698         }
699         else
700         {
701           bit = 0;
702         }
703       }
704 
705       result = (exponent << 52) | mantissa;
706     }
707     else
708     {
709       // Smaller than min_subnormal_float, truncate to zero.
710       result = 0LL;
711     }
712   }
713   else
714   {
715     // Larger than max_normal_float, truncate to this value.
716     result = 0x7FEFFFFFFFFFFFFFLL;
717   }
718 
719   if (sign < 0)
720   {
721     result |= 0x8000000000000000LL;
722   }
723   value = *(double*)&result;
724 }
725 
726 
727 template <int N>
toDouble()728 double Rational<N>::toDouble() const
729 {
730   double d = 0.;
731   convertTo(d);
732   return d;
733 }
734 
735 #endif
736